From e5f281e6bec23481cb7c53beffea005fe82fac65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yi=C4=9Fit=20=C3=87olako=C4=9Flu?= Date: Fri, 26 Feb 2021 00:07:09 +0300 Subject: [PATCH] Starting switching to suckless utilities --- .gitmodules | 3 + chroot/AUR.txt | 23 +- chroot/nonAUR.txt | 59 +- gtk/gtk-3.0/settings.ini | 4 +- gtk/themes/material-ocean | 1 + install.sh | 3 +- misc/rofi/config.rasi | 149 - misc/rofi/music_menu | 10 - misc/rofi/sidebar-mod.rasi | 109 - misc/rofi/themes/denvit.rasi | 149 - misc/rofi/themes/dmenu.rasi | 44 - scripts/dmenu-bluetooth | 290 ++ scripts/dmenu-logout | 2 +- scripts/edit_screen.sh | 5 + scripts/layoutmenu.sh | 7 + scripts/networkmanager_dmenu | 874 ++++ scripts/status-bar/arch | 2 +- scripts/status-bar/arch-block | 17 - scripts/status-bar/battery | 20 +- scripts/status-bar/battery-blocks | 49 - scripts/status-bar/capslock | 14 - scripts/status-bar/clima | 12 - scripts/status-bar/clima-icon | 27 - scripts/status-bar/cpu-temp | 2 +- scripts/status-bar/fecha | 9 - scripts/status-bar/fecha-block | 11 - scripts/status-bar/listener | 10 - scripts/status-bar/network | 19 + scripts/status-bar/red | 9 - scripts/status-bar/red-texto | 14 - scripts/status-bar/sep1 | 3 - scripts/status-bar/spotify-bar | 14 - scripts/status-bar/spotify-block | 17 - scripts/status-bar/spotify_status.py | 122 - scripts/status-bar/time | 9 + scripts/status-bar/volume | 24 - scripts/status-bar/volume-block | 29 - scripts/status-bar/weather | 31 + scripts/surf_linkselect.sh | 76 + suckless/clipmenu/.travis.yml | 10 + suckless/clipmenu/LICENSE | 5 + suckless/clipmenu/Makefile | 12 + suckless/clipmenu/README.md | 100 + suckless/clipmenu/clipctl | 52 + suckless/clipmenu/clipdel | 93 + suckless/clipmenu/clipfsck | 28 + suckless/clipmenu/clipmenu | 71 + suckless/clipmenu/clipmenud | 253 ++ suckless/clipmenu/init/clipmenud.service | 21 + suckless/clipmenu/tests/test-clipmenu | 93 + suckless/clipmenu/tests/test-perf | 87 + suckless/dwm/, | 245 -- suckless/dwm/.gitignore | 5 + suckless/dwm/Makefile | 24 +- suckless/dwm/Makefile.bak | 50 - suckless/dwm/README | 48 + suckless/dwm/README.es.org | 32 - suckless/dwm/README.md | 690 ++++ suckless/dwm/README.org | 35 - suckless/dwm/config.bak | 33 + suckless/dwm/config.h | 263 +- suckless/dwm/config.mk | 26 +- suckless/dwm/drw.c | 267 +- suckless/dwm/drw.h | 57 +- .../dwm/dwm-systray-20200914-61bb8b2.diff | 727 ---- suckless/dwm/dwm.1 | 9 - suckless/dwm/dwm.c | 3515 +++++++++++++---- suckless/dwm/dwm_config_pulseaudio.h | 28 - suckless/dwm/fibonacci.c | 66 - suckless/dwm/flexipatch-finalizer.sh | 345 ++ suckless/dwm/keybind.h | 132 + suckless/dwm/layouts.c | 27 - suckless/dwm/patch/aspectresize.c | 24 + suckless/dwm/patch/aspectresize.h | 1 + suckless/dwm/patch/attachx.c | 42 + suckless/dwm/patch/attachx.h | 1 + suckless/dwm/patch/autostart.c | 83 + suckless/dwm/patch/autostart.h | 1 + suckless/dwm/patch/bar_alpha.c | 42 + suckless/dwm/patch/bar_alpha.h | 3 + suckless/dwm/patch/bar_alternativetags.c | 6 + suckless/dwm/patch/bar_alternativetags.h | 1 + suckless/dwm/patch/bar_anybar.c | 82 + suckless/dwm/patch/bar_anybar.h | 4 + suckless/dwm/patch/bar_awesomebar.c | 79 + suckless/dwm/patch/bar_awesomebar.h | 3 + suckless/dwm/patch/bar_dwmblocks.c | 31 + suckless/dwm/patch/bar_dwmblocks.h | 2 + suckless/dwm/patch/bar_ewmhtags.c | 52 + suckless/dwm/patch/bar_ewmhtags.h | 6 + suckless/dwm/patch/bar_fancybar.c | 70 + suckless/dwm/patch/bar_fancybar.h | 3 + suckless/dwm/patch/bar_flexwintitle.c | 436 ++ suckless/dwm/patch/bar_flexwintitle.h | 10 + suckless/dwm/patch/bar_holdbar.c | 37 + suckless/dwm/patch/bar_holdbar.h | 2 + suckless/dwm/patch/bar_indicators.c | 110 + suckless/dwm/patch/bar_indicators.h | 20 + suckless/dwm/patch/bar_layoutmenu.c | 18 + suckless/dwm/patch/bar_layoutmenu.h | 1 + suckless/dwm/patch/bar_ltsymbol.c | 17 + suckless/dwm/patch/bar_ltsymbol.h | 3 + suckless/dwm/patch/bar_powerline_status.c | 121 + suckless/dwm/patch/bar_powerline_status.h | 11 + suckless/dwm/patch/bar_powerline_tags.c | 106 + suckless/dwm/patch/bar_powerline_tags.h | 3 + suckless/dwm/patch/bar_status.c | 33 + suckless/dwm/patch/bar_status.h | 9 + suckless/dwm/patch/bar_status2d.c | 262 ++ suckless/dwm/patch/bar_status2d.h | 13 + suckless/dwm/patch/bar_statusbutton.c | 17 + suckless/dwm/patch/bar_statusbutton.h | 3 + suckless/dwm/patch/bar_statuscmd.c | 74 + suckless/dwm/patch/bar_statuscmd.h | 6 + suckless/dwm/patch/bar_statuscolors.c | 23 + suckless/dwm/patch/bar_systray.c | 197 + suckless/dwm/patch/bar_systray.h | 41 + suckless/dwm/patch/bar_tabgroups.c | 220 ++ suckless/dwm/patch/bar_tabgroups.h | 7 + suckless/dwm/patch/bar_taggrid.c | 149 + suckless/dwm/patch/bar_taggrid.h | 4 + suckless/dwm/patch/bar_tagicons.c | 20 + suckless/dwm/patch/bar_tagicons.h | 7 + suckless/dwm/patch/bar_tags.c | 88 + suckless/dwm/patch/bar_tags.h | 3 + suckless/dwm/patch/bar_vtcolors.c | 68 + suckless/dwm/patch/bar_vtcolors.h | 2 + suckless/dwm/patch/bar_wintitle.c | 51 + suckless/dwm/patch/bar_wintitle.h | 3 + suckless/dwm/patch/bar_wintitle_floating.c | 45 + suckless/dwm/patch/bar_wintitle_floating.h | 8 + suckless/dwm/patch/bar_wintitle_hidden.c | 45 + suckless/dwm/patch/bar_wintitle_hidden.h | 8 + suckless/dwm/patch/bar_wintitleactions.c | 93 + suckless/dwm/patch/bar_wintitleactions.h | 5 + suckless/dwm/patch/cfacts.c | 23 + suckless/dwm/patch/cfacts.h | 1 + suckless/dwm/patch/cmdcustomize.c | 5 + suckless/dwm/patch/cmdcustomize.h | 1 + suckless/dwm/patch/combo.c | 49 + suckless/dwm/patch/combo.h | 5 + suckless/dwm/patch/cool_autostart.c | 28 + suckless/dwm/patch/cool_autostart.h | 1 + suckless/dwm/patch/cyclelayouts.c | 17 + suckless/dwm/patch/cyclelayouts.h | 1 + suckless/dwm/patch/decorationhints.c | 38 + suckless/dwm/patch/decorationhints.h | 8 + suckless/dwm/patch/dragcfact.c | 82 + suckless/dwm/patch/dragcfact.h | 1 + suckless/dwm/patch/dragmfact.c | 231 ++ suckless/dwm/patch/dragmfact.h | 1 + suckless/dwm/patch/dwmc | 129 + suckless/dwm/patch/dwmc.c | 100 + suckless/dwm/patch/dwmc.h | 13 + suckless/dwm/patch/exresize.c | 195 + suckless/dwm/patch/exresize.h | 8 + suckless/dwm/patch/fakefullscreenclient.c | 18 + suckless/dwm/patch/fakefullscreenclient.h | 1 + suckless/dwm/patch/floatpos.c | 195 + suckless/dwm/patch/floatpos.h | 3 + suckless/dwm/patch/focusadjacenttag.c | 73 + suckless/dwm/patch/focusadjacenttag.h | 6 + suckless/dwm/patch/focusdir.c | 65 + suckless/dwm/patch/focusdir.h | 1 + suckless/dwm/patch/focusmaster.c | 13 + suckless/dwm/patch/focusmaster.h | 1 + suckless/dwm/patch/focusurgent.c | 15 + suckless/dwm/patch/focusurgent.h | 1 + suckless/dwm/patch/fsignal.c | 40 + suckless/dwm/patch/fsignal.h | 7 + suckless/dwm/patch/fullscreen.c | 17 + suckless/dwm/patch/fullscreen.h | 1 + suckless/dwm/patch/include.c | 343 ++ suckless/dwm/patch/include.h | 333 ++ suckless/dwm/patch/inplacerotate.c | 53 + suckless/dwm/patch/inplacerotate.h | 1 + suckless/dwm/patch/insets.c | 18 + suckless/dwm/patch/insets.h | 2 + suckless/dwm/patch/ipc.c | 101 + suckless/dwm/patch/ipc.h | 6 + suckless/dwm/patch/ipc/IPCClient.c | 66 + suckless/dwm/patch/ipc/IPCClient.h | 61 + suckless/dwm/patch/ipc/dwm-msg.c | 548 +++ suckless/dwm/patch/ipc/ipc.c | 1201 ++++++ suckless/dwm/patch/ipc/ipc.h | 319 ++ suckless/dwm/patch/ipc/util.c | 135 + suckless/dwm/patch/ipc/util.h | 4 + suckless/dwm/patch/ipc/yajl_dumps.c | 351 ++ suckless/dwm/patch/ipc/yajl_dumps.h | 65 + suckless/dwm/patch/keymodes.c | 143 + suckless/dwm/patch/keymodes.h | 21 + suckless/dwm/patch/killunsel.c | 27 + suckless/dwm/patch/killunsel.h | 1 + suckless/dwm/patch/layout_bstack.c | 74 + suckless/dwm/patch/layout_bstack.h | 1 + suckless/dwm/patch/layout_bstackhoriz.c | 76 + suckless/dwm/patch/layout_bstackhoriz.h | 1 + .../dwm/patch/layout_centeredfloatingmaster.c | 94 + .../dwm/patch/layout_centeredfloatingmaster.h | 1 + suckless/dwm/patch/layout_centeredmaster.c | 159 + suckless/dwm/patch/layout_centeredmaster.h | 1 + suckless/dwm/patch/layout_columns.c | 73 + suckless/dwm/patch/layout_columns.h | 1 + suckless/dwm/patch/layout_deck.c | 66 + suckless/dwm/patch/layout_deck.h | 1 + suckless/dwm/patch/layout_facts.c | 51 + suckless/dwm/patch/layout_fibonacci.c | 190 + suckless/dwm/patch/layout_fibonacci.h | 7 + suckless/dwm/patch/layout_flextile-deluxe.c | 890 +++++ suckless/dwm/patch/layout_flextile-deluxe.h | 120 + suckless/dwm/patch/layout_gapplessgrid.c | 98 + suckless/dwm/patch/layout_gapplessgrid.h | 1 + suckless/dwm/patch/layout_grid.c | 60 + suckless/dwm/patch/layout_grid.h | 1 + suckless/dwm/patch/layout_horizgrid.c | 103 + suckless/dwm/patch/layout_horizgrid.h | 1 + suckless/dwm/patch/layout_monocle.c | 37 + suckless/dwm/patch/layout_monocle.h | 1 + suckless/dwm/patch/layout_nrowgrid.c | 103 + suckless/dwm/patch/layout_nrowgrid.h | 1 + suckless/dwm/patch/layout_tile.c | 73 + suckless/dwm/patch/layout_tile.h | 1 + suckless/dwm/patch/layoutmenu.sh | 8 + suckless/dwm/patch/maximize.c | 69 + suckless/dwm/patch/maximize.h | 4 + suckless/dwm/patch/moveplace.c | 29 + suckless/dwm/patch/moveplace.h | 3 + suckless/dwm/patch/moveresize.c | 64 + suckless/dwm/patch/moveresize.h | 1 + suckless/dwm/{ => patch}/movestack.c | 43 +- suckless/dwm/patch/movestack.h | 1 + suckless/dwm/patch/mpdcontrol.c | 144 + suckless/dwm/patch/mpdcontrol.h | 2 + suckless/dwm/patch/nomodbuttons.c | 7 + suckless/dwm/patch/nomodbuttons.h | 1 + suckless/dwm/patch/pertag.c | 69 + suckless/dwm/patch/pertag.h | 1 + suckless/dwm/patch/placemouse.c | 151 + suckless/dwm/patch/placemouse.h | 6 + suckless/dwm/patch/push.c | 71 + suckless/dwm/patch/push.h | 4 + suckless/dwm/patch/push_no_master.c | 43 + suckless/dwm/patch/push_no_master.h | 3 + suckless/dwm/patch/reorganizetags.c | 27 + suckless/dwm/patch/reorganizetags.h | 1 + suckless/dwm/patch/restartsig.c | 15 + suckless/dwm/patch/restartsig.h | 2 + suckless/dwm/patch/riodraw.c | 103 + suckless/dwm/patch/riodraw.h | 5 + suckless/dwm/patch/rotatestack.c | 52 + suckless/dwm/patch/rotatestack.h | 3 + suckless/dwm/patch/roundedcorners.c | 50 + suckless/dwm/patch/roundedcorners.h | 1 + suckless/dwm/patch/scratchpad.c | 76 + suckless/dwm/patch/scratchpad.h | 8 + suckless/dwm/patch/scratchpad_alt_1.c | 92 + suckless/dwm/patch/scratchpad_alt_1.h | 8 + suckless/dwm/patch/selfrestart.c | 68 + suckless/dwm/patch/selfrestart.h | 2 + suckless/dwm/patch/setborderpx.c | 44 + suckless/dwm/patch/setborderpx.h | 1 + suckless/dwm/patch/shiftview.c | 18 + suckless/dwm/patch/shiftview.h | 1 + suckless/dwm/patch/shiftviewclients.c | 42 + suckless/dwm/patch/shiftviewclients.h | 1 + suckless/dwm/patch/sizehints_ruled.c | 24 + suckless/dwm/patch/sizehints_ruled.h | 1 + suckless/dwm/patch/sortscreens.c | 15 + suckless/dwm/patch/sortscreens.h | 3 + suckless/dwm/patch/stacker.c | 106 + suckless/dwm/patch/stacker.h | 10 + suckless/dwm/patch/sticky.c | 8 + suckless/dwm/patch/sticky.h | 1 + suckless/dwm/patch/swallow.c | 205 + suckless/dwm/patch/swallow.h | 7 + suckless/dwm/patch/swapfocus.c | 21 + suckless/dwm/patch/swapfocus.h | 1 + suckless/dwm/patch/swaptags.c | 22 + suckless/dwm/patch/swaptags.h | 1 + suckless/dwm/patch/switchcol.c | 28 + suckless/dwm/patch/switchcol.h | 1 + suckless/dwm/patch/tagall.c | 25 + suckless/dwm/patch/tagall.h | 1 + suckless/dwm/patch/tagallmon.c | 48 + suckless/dwm/patch/tagallmon.h | 1 + suckless/dwm/patch/tagothermonitor.c | 43 + suckless/dwm/patch/tagothermonitor.h | 8 + suckless/dwm/patch/tagswapmon.c | 74 + suckless/dwm/patch/tagswapmon.h | 1 + suckless/dwm/patch/togglefullscreen.c | 17 + suckless/dwm/patch/togglefullscreen.h | 1 + suckless/dwm/patch/transfer.c | 33 + suckless/dwm/patch/transfer.h | 1 + suckless/dwm/patch/transferall.c | 25 + suckless/dwm/patch/transferall.h | 1 + suckless/dwm/patch/unfloatvisible.c | 14 + suckless/dwm/patch/unfloatvisible.h | 1 + suckless/dwm/patch/vanitygaps.c | 192 + suckless/dwm/patch/vanitygaps.h | 19 + suckless/dwm/patch/warp.c | 37 + suckless/dwm/patch/warp.h | 1 + suckless/dwm/patch/winview.c | 20 + suckless/dwm/patch/winview.h | 1 + suckless/dwm/patch/xrdb.c | 125 + suckless/dwm/patch/xrdb.h | 21 + suckless/dwm/patch/zoomswap.c | 13 + suckless/dwm/patch/zoomswap.h | 1 + suckless/dwm/patches.def.h | 1178 ++++++ suckless/dwm/patches/dwm-6.0-winview.diff | 65 - ...dwm-actualfullscreen-20191112-cb3f58a.diff | 53 - ...-alttagsdecoration-2020010304-cb3f58a.diff | 67 - .../dwm-alwayscenter-20200625-f04cac6.diff | 12 - .../dwm-barpadding-20200720-bb2e722.diff | 124 - .../dwm/patches/dwm-centeredmaster-6.1.diff | 142 - .../patches/dwm-cfacts-20200913-61bb8b2.diff | 117 - .../dwm-cfacts_centeredmaster-6.2.diff | 180 - suckless/dwm/patches/dwm-colorbar-6.2.diff | 68 - .../dwm-cyclelayouts-20180524-6.2.diff | 93 - suckless/dwm/patches/dwm-deck-6.0.diff | 90 - suckless/dwm/patches/dwm-dwmblocks-6.2.diff | 340 -- suckless/dwm/patches/dwm-ewmhtags-6.2.diff | 161 - suckless/dwm/patches/dwm-fibonacci-5.8.2.diff | 85 - suckless/dwm/patches/dwm-fixborders-6.2.diff | 27 - .../dwm-gridmode-20170909-ceac8c9.diff | 73 - .../dwm/patches/dwm-inplacerotate-6.2.diff | 108 - .../dwm-leftlayout-20180524-c8e9479.diff | 69 - suckless/dwm/patches/dwm-movestack-6.1.diff | 73 - .../dwm-netclientliststacking-6.2.diff | 65 - .../patches/dwm-pertag-20170513-ceac8c9.diff | 177 - suckless/dwm/patches/dwm-rmaster-6.1.diff | 113 - .../dwm-statuspadding-20150524-c8e9479.diff | 62 - suckless/dwm/patches/dwm-switchcol-6.1.diff | 47 - .../patches/dwm-systray-20200914-61bb8b2.diff | 727 ---- suckless/dwm/patches/dwm-uselessgap-6.2.diff | 81 - suckless/dwm/rules.h | 22 + suckless/dwm/shiftview.c | 19 - suckless/dwm/theme.h | 39 + suckless/dwm/util.h | 10 + suckless/dwmblocks/.gitignore | 54 +- suckless/dwmblocks/FUNDING.yml | 3 + suckless/dwmblocks/GNUmakefile | 32 - suckless/dwmblocks/LICENSE | 340 +- suckless/dwmblocks/Makefile | 19 + suckless/dwmblocks/README.md | 76 +- suckless/dwmblocks/blocks.h | 33 - suckless/dwmblocks/config.h | 20 + suckless/dwmblocks/dwmblocks.c | 523 +-- .../patches/dwmblocks-statuscmd-fork.diff | 77 + .../patches/dwmblocks-statuscmd-signal.diff | 93 + suckless/dwmblocks/sigdwmblocks.c | 76 - suckless/dwmblocks/xgetrootname.c | 21 - xorg/Xresources | 23 + xorg/xinitrc | 2 +- 353 files changed, 21606 insertions(+), 6930 deletions(-) create mode 100644 .gitmodules create mode 160000 gtk/themes/material-ocean delete mode 100644 misc/rofi/config.rasi delete mode 100755 misc/rofi/music_menu delete mode 100644 misc/rofi/sidebar-mod.rasi delete mode 100644 misc/rofi/themes/denvit.rasi delete mode 100644 misc/rofi/themes/dmenu.rasi create mode 100755 scripts/dmenu-bluetooth create mode 100755 scripts/edit_screen.sh create mode 100755 scripts/layoutmenu.sh create mode 100755 scripts/networkmanager_dmenu delete mode 100755 scripts/status-bar/arch-block delete mode 100755 scripts/status-bar/battery-blocks delete mode 100755 scripts/status-bar/capslock delete mode 100755 scripts/status-bar/clima delete mode 100755 scripts/status-bar/clima-icon delete mode 100755 scripts/status-bar/fecha delete mode 100755 scripts/status-bar/fecha-block delete mode 100755 scripts/status-bar/listener create mode 100755 scripts/status-bar/network delete mode 100755 scripts/status-bar/red delete mode 100755 scripts/status-bar/red-texto delete mode 100755 scripts/status-bar/sep1 delete mode 100755 scripts/status-bar/spotify-bar delete mode 100755 scripts/status-bar/spotify-block delete mode 100755 scripts/status-bar/spotify_status.py create mode 100755 scripts/status-bar/time delete mode 100755 scripts/status-bar/volume delete mode 100755 scripts/status-bar/volume-block create mode 100755 scripts/status-bar/weather create mode 100755 scripts/surf_linkselect.sh create mode 100644 suckless/clipmenu/.travis.yml create mode 100644 suckless/clipmenu/LICENSE create mode 100644 suckless/clipmenu/Makefile create mode 100644 suckless/clipmenu/README.md create mode 100755 suckless/clipmenu/clipctl create mode 100755 suckless/clipmenu/clipdel create mode 100755 suckless/clipmenu/clipfsck create mode 100755 suckless/clipmenu/clipmenu create mode 100755 suckless/clipmenu/clipmenud create mode 100644 suckless/clipmenu/init/clipmenud.service create mode 100755 suckless/clipmenu/tests/test-clipmenu create mode 100755 suckless/clipmenu/tests/test-perf delete mode 100644 suckless/dwm/, create mode 100644 suckless/dwm/.gitignore delete mode 100644 suckless/dwm/Makefile.bak create mode 100644 suckless/dwm/README delete mode 100644 suckless/dwm/README.es.org create mode 100644 suckless/dwm/README.md delete mode 100644 suckless/dwm/README.org create mode 100644 suckless/dwm/config.bak delete mode 100644 suckless/dwm/dwm-systray-20200914-61bb8b2.diff delete mode 100644 suckless/dwm/dwm_config_pulseaudio.h delete mode 100644 suckless/dwm/fibonacci.c create mode 100755 suckless/dwm/flexipatch-finalizer.sh create mode 100644 suckless/dwm/keybind.h delete mode 100644 suckless/dwm/layouts.c create mode 100644 suckless/dwm/patch/aspectresize.c create mode 100644 suckless/dwm/patch/aspectresize.h create mode 100644 suckless/dwm/patch/attachx.c create mode 100644 suckless/dwm/patch/attachx.h create mode 100644 suckless/dwm/patch/autostart.c create mode 100644 suckless/dwm/patch/autostart.h create mode 100644 suckless/dwm/patch/bar_alpha.c create mode 100644 suckless/dwm/patch/bar_alpha.h create mode 100644 suckless/dwm/patch/bar_alternativetags.c create mode 100644 suckless/dwm/patch/bar_alternativetags.h create mode 100644 suckless/dwm/patch/bar_anybar.c create mode 100644 suckless/dwm/patch/bar_anybar.h create mode 100644 suckless/dwm/patch/bar_awesomebar.c create mode 100644 suckless/dwm/patch/bar_awesomebar.h create mode 100644 suckless/dwm/patch/bar_dwmblocks.c create mode 100644 suckless/dwm/patch/bar_dwmblocks.h create mode 100644 suckless/dwm/patch/bar_ewmhtags.c create mode 100644 suckless/dwm/patch/bar_ewmhtags.h create mode 100644 suckless/dwm/patch/bar_fancybar.c create mode 100644 suckless/dwm/patch/bar_fancybar.h create mode 100644 suckless/dwm/patch/bar_flexwintitle.c create mode 100644 suckless/dwm/patch/bar_flexwintitle.h create mode 100644 suckless/dwm/patch/bar_holdbar.c create mode 100644 suckless/dwm/patch/bar_holdbar.h create mode 100644 suckless/dwm/patch/bar_indicators.c create mode 100644 suckless/dwm/patch/bar_indicators.h create mode 100644 suckless/dwm/patch/bar_layoutmenu.c create mode 100644 suckless/dwm/patch/bar_layoutmenu.h create mode 100644 suckless/dwm/patch/bar_ltsymbol.c create mode 100644 suckless/dwm/patch/bar_ltsymbol.h create mode 100644 suckless/dwm/patch/bar_powerline_status.c create mode 100644 suckless/dwm/patch/bar_powerline_status.h create mode 100644 suckless/dwm/patch/bar_powerline_tags.c create mode 100644 suckless/dwm/patch/bar_powerline_tags.h create mode 100644 suckless/dwm/patch/bar_status.c create mode 100644 suckless/dwm/patch/bar_status.h create mode 100644 suckless/dwm/patch/bar_status2d.c create mode 100644 suckless/dwm/patch/bar_status2d.h create mode 100644 suckless/dwm/patch/bar_statusbutton.c create mode 100644 suckless/dwm/patch/bar_statusbutton.h create mode 100644 suckless/dwm/patch/bar_statuscmd.c create mode 100644 suckless/dwm/patch/bar_statuscmd.h create mode 100644 suckless/dwm/patch/bar_statuscolors.c create mode 100644 suckless/dwm/patch/bar_systray.c create mode 100644 suckless/dwm/patch/bar_systray.h create mode 100644 suckless/dwm/patch/bar_tabgroups.c create mode 100644 suckless/dwm/patch/bar_tabgroups.h create mode 100644 suckless/dwm/patch/bar_taggrid.c create mode 100644 suckless/dwm/patch/bar_taggrid.h create mode 100644 suckless/dwm/patch/bar_tagicons.c create mode 100644 suckless/dwm/patch/bar_tagicons.h create mode 100644 suckless/dwm/patch/bar_tags.c create mode 100644 suckless/dwm/patch/bar_tags.h create mode 100644 suckless/dwm/patch/bar_vtcolors.c create mode 100644 suckless/dwm/patch/bar_vtcolors.h create mode 100644 suckless/dwm/patch/bar_wintitle.c create mode 100644 suckless/dwm/patch/bar_wintitle.h create mode 100644 suckless/dwm/patch/bar_wintitle_floating.c create mode 100644 suckless/dwm/patch/bar_wintitle_floating.h create mode 100644 suckless/dwm/patch/bar_wintitle_hidden.c create mode 100644 suckless/dwm/patch/bar_wintitle_hidden.h create mode 100644 suckless/dwm/patch/bar_wintitleactions.c create mode 100644 suckless/dwm/patch/bar_wintitleactions.h create mode 100644 suckless/dwm/patch/cfacts.c create mode 100644 suckless/dwm/patch/cfacts.h create mode 100644 suckless/dwm/patch/cmdcustomize.c create mode 100644 suckless/dwm/patch/cmdcustomize.h create mode 100644 suckless/dwm/patch/combo.c create mode 100644 suckless/dwm/patch/combo.h create mode 100644 suckless/dwm/patch/cool_autostart.c create mode 100644 suckless/dwm/patch/cool_autostart.h create mode 100644 suckless/dwm/patch/cyclelayouts.c create mode 100644 suckless/dwm/patch/cyclelayouts.h create mode 100644 suckless/dwm/patch/decorationhints.c create mode 100644 suckless/dwm/patch/decorationhints.h create mode 100644 suckless/dwm/patch/dragcfact.c create mode 100644 suckless/dwm/patch/dragcfact.h create mode 100644 suckless/dwm/patch/dragmfact.c create mode 100644 suckless/dwm/patch/dragmfact.h create mode 100755 suckless/dwm/patch/dwmc create mode 100644 suckless/dwm/patch/dwmc.c create mode 100644 suckless/dwm/patch/dwmc.h create mode 100644 suckless/dwm/patch/exresize.c create mode 100644 suckless/dwm/patch/exresize.h create mode 100644 suckless/dwm/patch/fakefullscreenclient.c create mode 100644 suckless/dwm/patch/fakefullscreenclient.h create mode 100644 suckless/dwm/patch/floatpos.c create mode 100644 suckless/dwm/patch/floatpos.h create mode 100644 suckless/dwm/patch/focusadjacenttag.c create mode 100644 suckless/dwm/patch/focusadjacenttag.h create mode 100644 suckless/dwm/patch/focusdir.c create mode 100644 suckless/dwm/patch/focusdir.h create mode 100644 suckless/dwm/patch/focusmaster.c create mode 100644 suckless/dwm/patch/focusmaster.h create mode 100644 suckless/dwm/patch/focusurgent.c create mode 100644 suckless/dwm/patch/focusurgent.h create mode 100644 suckless/dwm/patch/fsignal.c create mode 100644 suckless/dwm/patch/fsignal.h create mode 100644 suckless/dwm/patch/fullscreen.c create mode 100644 suckless/dwm/patch/fullscreen.h create mode 100644 suckless/dwm/patch/include.c create mode 100644 suckless/dwm/patch/include.h create mode 100644 suckless/dwm/patch/inplacerotate.c create mode 100644 suckless/dwm/patch/inplacerotate.h create mode 100644 suckless/dwm/patch/insets.c create mode 100644 suckless/dwm/patch/insets.h create mode 100644 suckless/dwm/patch/ipc.c create mode 100644 suckless/dwm/patch/ipc.h create mode 100644 suckless/dwm/patch/ipc/IPCClient.c create mode 100644 suckless/dwm/patch/ipc/IPCClient.h create mode 100644 suckless/dwm/patch/ipc/dwm-msg.c create mode 100644 suckless/dwm/patch/ipc/ipc.c create mode 100644 suckless/dwm/patch/ipc/ipc.h create mode 100644 suckless/dwm/patch/ipc/util.c create mode 100644 suckless/dwm/patch/ipc/util.h create mode 100644 suckless/dwm/patch/ipc/yajl_dumps.c create mode 100644 suckless/dwm/patch/ipc/yajl_dumps.h create mode 100644 suckless/dwm/patch/keymodes.c create mode 100644 suckless/dwm/patch/keymodes.h create mode 100644 suckless/dwm/patch/killunsel.c create mode 100644 suckless/dwm/patch/killunsel.h create mode 100644 suckless/dwm/patch/layout_bstack.c create mode 100644 suckless/dwm/patch/layout_bstack.h create mode 100644 suckless/dwm/patch/layout_bstackhoriz.c create mode 100644 suckless/dwm/patch/layout_bstackhoriz.h create mode 100644 suckless/dwm/patch/layout_centeredfloatingmaster.c create mode 100644 suckless/dwm/patch/layout_centeredfloatingmaster.h create mode 100644 suckless/dwm/patch/layout_centeredmaster.c create mode 100644 suckless/dwm/patch/layout_centeredmaster.h create mode 100644 suckless/dwm/patch/layout_columns.c create mode 100644 suckless/dwm/patch/layout_columns.h create mode 100644 suckless/dwm/patch/layout_deck.c create mode 100644 suckless/dwm/patch/layout_deck.h create mode 100644 suckless/dwm/patch/layout_facts.c create mode 100644 suckless/dwm/patch/layout_fibonacci.c create mode 100644 suckless/dwm/patch/layout_fibonacci.h create mode 100644 suckless/dwm/patch/layout_flextile-deluxe.c create mode 100644 suckless/dwm/patch/layout_flextile-deluxe.h create mode 100644 suckless/dwm/patch/layout_gapplessgrid.c create mode 100644 suckless/dwm/patch/layout_gapplessgrid.h create mode 100644 suckless/dwm/patch/layout_grid.c create mode 100644 suckless/dwm/patch/layout_grid.h create mode 100644 suckless/dwm/patch/layout_horizgrid.c create mode 100644 suckless/dwm/patch/layout_horizgrid.h create mode 100644 suckless/dwm/patch/layout_monocle.c create mode 100644 suckless/dwm/patch/layout_monocle.h create mode 100644 suckless/dwm/patch/layout_nrowgrid.c create mode 100644 suckless/dwm/patch/layout_nrowgrid.h create mode 100644 suckless/dwm/patch/layout_tile.c create mode 100644 suckless/dwm/patch/layout_tile.h create mode 100755 suckless/dwm/patch/layoutmenu.sh create mode 100644 suckless/dwm/patch/maximize.c create mode 100644 suckless/dwm/patch/maximize.h create mode 100644 suckless/dwm/patch/moveplace.c create mode 100644 suckless/dwm/patch/moveplace.h create mode 100644 suckless/dwm/patch/moveresize.c create mode 100644 suckless/dwm/patch/moveresize.h rename suckless/dwm/{ => patch}/movestack.c (50%) create mode 100644 suckless/dwm/patch/movestack.h create mode 100644 suckless/dwm/patch/mpdcontrol.c create mode 100644 suckless/dwm/patch/mpdcontrol.h create mode 100644 suckless/dwm/patch/nomodbuttons.c create mode 100644 suckless/dwm/patch/nomodbuttons.h create mode 100644 suckless/dwm/patch/pertag.c create mode 100644 suckless/dwm/patch/pertag.h create mode 100644 suckless/dwm/patch/placemouse.c create mode 100644 suckless/dwm/patch/placemouse.h create mode 100644 suckless/dwm/patch/push.c create mode 100644 suckless/dwm/patch/push.h create mode 100644 suckless/dwm/patch/push_no_master.c create mode 100644 suckless/dwm/patch/push_no_master.h create mode 100644 suckless/dwm/patch/reorganizetags.c create mode 100644 suckless/dwm/patch/reorganizetags.h create mode 100644 suckless/dwm/patch/restartsig.c create mode 100644 suckless/dwm/patch/restartsig.h create mode 100644 suckless/dwm/patch/riodraw.c create mode 100644 suckless/dwm/patch/riodraw.h create mode 100644 suckless/dwm/patch/rotatestack.c create mode 100644 suckless/dwm/patch/rotatestack.h create mode 100644 suckless/dwm/patch/roundedcorners.c create mode 100644 suckless/dwm/patch/roundedcorners.h create mode 100644 suckless/dwm/patch/scratchpad.c create mode 100644 suckless/dwm/patch/scratchpad.h create mode 100644 suckless/dwm/patch/scratchpad_alt_1.c create mode 100644 suckless/dwm/patch/scratchpad_alt_1.h create mode 100644 suckless/dwm/patch/selfrestart.c create mode 100644 suckless/dwm/patch/selfrestart.h create mode 100644 suckless/dwm/patch/setborderpx.c create mode 100644 suckless/dwm/patch/setborderpx.h create mode 100644 suckless/dwm/patch/shiftview.c create mode 100644 suckless/dwm/patch/shiftview.h create mode 100644 suckless/dwm/patch/shiftviewclients.c create mode 100644 suckless/dwm/patch/shiftviewclients.h create mode 100644 suckless/dwm/patch/sizehints_ruled.c create mode 100644 suckless/dwm/patch/sizehints_ruled.h create mode 100644 suckless/dwm/patch/sortscreens.c create mode 100644 suckless/dwm/patch/sortscreens.h create mode 100644 suckless/dwm/patch/stacker.c create mode 100644 suckless/dwm/patch/stacker.h create mode 100644 suckless/dwm/patch/sticky.c create mode 100644 suckless/dwm/patch/sticky.h create mode 100644 suckless/dwm/patch/swallow.c create mode 100644 suckless/dwm/patch/swallow.h create mode 100644 suckless/dwm/patch/swapfocus.c create mode 100644 suckless/dwm/patch/swapfocus.h create mode 100644 suckless/dwm/patch/swaptags.c create mode 100644 suckless/dwm/patch/swaptags.h create mode 100644 suckless/dwm/patch/switchcol.c create mode 100644 suckless/dwm/patch/switchcol.h create mode 100644 suckless/dwm/patch/tagall.c create mode 100644 suckless/dwm/patch/tagall.h create mode 100644 suckless/dwm/patch/tagallmon.c create mode 100644 suckless/dwm/patch/tagallmon.h create mode 100644 suckless/dwm/patch/tagothermonitor.c create mode 100644 suckless/dwm/patch/tagothermonitor.h create mode 100644 suckless/dwm/patch/tagswapmon.c create mode 100644 suckless/dwm/patch/tagswapmon.h create mode 100644 suckless/dwm/patch/togglefullscreen.c create mode 100644 suckless/dwm/patch/togglefullscreen.h create mode 100644 suckless/dwm/patch/transfer.c create mode 100644 suckless/dwm/patch/transfer.h create mode 100644 suckless/dwm/patch/transferall.c create mode 100644 suckless/dwm/patch/transferall.h create mode 100644 suckless/dwm/patch/unfloatvisible.c create mode 100644 suckless/dwm/patch/unfloatvisible.h create mode 100644 suckless/dwm/patch/vanitygaps.c create mode 100644 suckless/dwm/patch/vanitygaps.h create mode 100644 suckless/dwm/patch/warp.c create mode 100644 suckless/dwm/patch/warp.h create mode 100644 suckless/dwm/patch/winview.c create mode 100644 suckless/dwm/patch/winview.h create mode 100644 suckless/dwm/patch/xrdb.c create mode 100644 suckless/dwm/patch/xrdb.h create mode 100644 suckless/dwm/patch/zoomswap.c create mode 100644 suckless/dwm/patch/zoomswap.h create mode 100644 suckless/dwm/patches.def.h delete mode 100644 suckless/dwm/patches/dwm-6.0-winview.diff delete mode 100644 suckless/dwm/patches/dwm-actualfullscreen-20191112-cb3f58a.diff delete mode 100644 suckless/dwm/patches/dwm-alttagsdecoration-2020010304-cb3f58a.diff delete mode 100644 suckless/dwm/patches/dwm-alwayscenter-20200625-f04cac6.diff delete mode 100644 suckless/dwm/patches/dwm-barpadding-20200720-bb2e722.diff delete mode 100644 suckless/dwm/patches/dwm-centeredmaster-6.1.diff delete mode 100644 suckless/dwm/patches/dwm-cfacts-20200913-61bb8b2.diff delete mode 100644 suckless/dwm/patches/dwm-cfacts_centeredmaster-6.2.diff delete mode 100644 suckless/dwm/patches/dwm-colorbar-6.2.diff delete mode 100644 suckless/dwm/patches/dwm-cyclelayouts-20180524-6.2.diff delete mode 100644 suckless/dwm/patches/dwm-deck-6.0.diff delete mode 100644 suckless/dwm/patches/dwm-dwmblocks-6.2.diff delete mode 100644 suckless/dwm/patches/dwm-ewmhtags-6.2.diff delete mode 100644 suckless/dwm/patches/dwm-fibonacci-5.8.2.diff delete mode 100644 suckless/dwm/patches/dwm-fixborders-6.2.diff delete mode 100644 suckless/dwm/patches/dwm-gridmode-20170909-ceac8c9.diff delete mode 100644 suckless/dwm/patches/dwm-inplacerotate-6.2.diff delete mode 100644 suckless/dwm/patches/dwm-leftlayout-20180524-c8e9479.diff delete mode 100644 suckless/dwm/patches/dwm-movestack-6.1.diff delete mode 100644 suckless/dwm/patches/dwm-netclientliststacking-6.2.diff delete mode 100644 suckless/dwm/patches/dwm-pertag-20170513-ceac8c9.diff delete mode 100644 suckless/dwm/patches/dwm-rmaster-6.1.diff delete mode 100644 suckless/dwm/patches/dwm-statuspadding-20150524-c8e9479.diff delete mode 100644 suckless/dwm/patches/dwm-switchcol-6.1.diff delete mode 100644 suckless/dwm/patches/dwm-systray-20200914-61bb8b2.diff delete mode 100644 suckless/dwm/patches/dwm-uselessgap-6.2.diff create mode 100644 suckless/dwm/rules.h delete mode 100644 suckless/dwm/shiftview.c create mode 100644 suckless/dwm/theme.h create mode 100644 suckless/dwmblocks/FUNDING.yml delete mode 100644 suckless/dwmblocks/GNUmakefile create mode 100644 suckless/dwmblocks/Makefile delete mode 100644 suckless/dwmblocks/blocks.h create mode 100644 suckless/dwmblocks/config.h create mode 100644 suckless/dwmblocks/patches/dwmblocks-statuscmd-fork.diff create mode 100644 suckless/dwmblocks/patches/dwmblocks-statuscmd-signal.diff delete mode 100644 suckless/dwmblocks/sigdwmblocks.c delete mode 100644 suckless/dwmblocks/xgetrootname.c create mode 100644 xorg/Xresources diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..e0ee604a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "gtk/themes/material-ocean"] + path = gtk/themes/material-ocean + url = https://github.com/material-ocean/Gtk-Theme.git diff --git a/chroot/AUR.txt b/chroot/AUR.txt index 71992f4e..fdcbf8ed 100644 --- a/chroot/AUR.txt +++ b/chroot/AUR.txt @@ -1,37 +1,48 @@ activitywatch-bin aic94xx-firmware antibody +betterdiscord betterlockscreen +capt-src +checkupdates+aur +checkupdates-aur +cordless-bin direnv -gconf ghidra-darcula +git-secret gitkraken -gksu glxinfo +google-cloud-sdk i3lock-color ifuse jetbrains-toolbox -libgksu ly mailspring mconnect-git nerd-fonts-hack -ngrok numix-icon-theme-git +perl-checkupdates-aur +perl-www-aur plymouth-git plymouth-theme-cubes-git plymouth-theme-darth-vader-git postman-bin qt5-styleplugins rofi-bluetooth-git -rofi-dmenu +ruby-erubis +ruby-xdg spicetify-cli spotify spotify-tui sublime-text-3 +surf +terminal_dimensions-git +termpdf-git ttf-material-design-icons +ttf-symbola vue-cli wd719x-firmware whatsapp-nativefier-dark -yay +xmenu +yaft zoom diff --git a/chroot/nonAUR.txt b/chroot/nonAUR.txt index 36e0ddf7..b9c82250 100644 --- a/chroot/nonAUR.txt +++ b/chroot/nonAUR.txt @@ -1,3 +1,4 @@ +ack arandr arc-gtk-theme autoconf @@ -7,13 +8,18 @@ base bat binutils bison +blackarch-keyring blueman bluez-utils borgmatic calibre chrony -clipmenu cmake +code +conky +ctags +cups +cups-pdf discord dunst efibootmgr @@ -30,6 +36,7 @@ gcc gdm gettext git +gksu gnome-bluetooth gnome-keyring gparted @@ -38,17 +45,24 @@ grep groff grub gvfs-afc +gvim gzip +hexchat htop inetutils intel-ucode +ipython jdk11-openjdk +jq jre11-openjdk +keepass kitty libgnome-keyring +libreoffice-fresh libtool lightdm lightdm-gtk-greeter +lighttpd linux linux-firmware linux-headers @@ -59,10 +73,13 @@ mariadb mlocate mysql-workbench nemo +neofetch neovim net-tools networkmanager nextcloud-client +ngrok +noto-fonts noto-fonts-emoji npm ntfs-3g @@ -71,32 +88,68 @@ pacman pamixer patch pavucontrol +perl-image-exiftool +php picom +pkgconf playerctl polkit-gnome pulseaudio pulseaudio-alsa pulseaudio-bluetooth +python-pdftotext +python-pip +python-pylint python-pynvim +python2 qt5ct +ranger +rclone redis refind +ripgrep rofi rsync sbsigntools +scrot sed shotwell +sonic-visualiser +stegoveritas sudo +sxiv +sysbench +system-config-printer +tcsh telegram-desktop termite texinfo +texlive-bibtexextra +texlive-core +texlive-fontsextra +texlive-formatsextra +texlive-games +texlive-humanities +texlive-latexextra +texlive-music +texlive-pictures +texlive-pstricks +texlive-publishers +texlive-science thunar +thunderbird +thunderbird-extension-enigmail +tmate tmux +tor +torbrowser-launcher tree ttf-dejavu +ttf-inconsolata +ttf-joypixels +ttf-linux-libertine unzip vi -vim virtualbox virtualbox-host-dkms vlc @@ -156,6 +209,8 @@ xorg-xwininfo xorg-xwud xss-lock xterm +yay youtube-dl zathura +zathura-pdf-mupdf zsh diff --git a/gtk/gtk-3.0/settings.ini b/gtk/gtk-3.0/settings.ini index 61a4fe7f..e4db405b 100644 --- a/gtk/gtk-3.0/settings.ini +++ b/gtk/gtk-3.0/settings.ini @@ -1,6 +1,6 @@ [Settings] -gtk-theme-name=Arc-Dark -gtk-icon-theme-name=Numix +gtk-theme-name=material-ocean +gtk-icon-theme-name=Tela-orange-dark gtk-font-name=Cantarell 11 gtk-cursor-theme-name=Adwaita gtk-cursor-theme-size=0 diff --git a/gtk/themes/material-ocean b/gtk/themes/material-ocean new file mode 160000 index 00000000..aaa7a1d9 --- /dev/null +++ b/gtk/themes/material-ocean @@ -0,0 +1 @@ +Subproject commit aaa7a1d92ce53ecddeab35faaf4d0648ae7f4e93 diff --git a/install.sh b/install.sh index 9c22e36f..0888a9c4 100755 --- a/install.sh +++ b/install.sh @@ -5,13 +5,13 @@ ln -s ~/.dotfiles/vim/vimrc ~/.vimrc ln -s ~/.dotfiles/vim/vim ~/.vim # GTK +ln -s ~/.dotfiles/gtk/themes ~/.themes ln -s ~/.dotfiles/gtk/gtk-2.0 ~/.config/gtk-2.0 ln -s ~/.dotfiles/gtk/gtk-3.0 ~/.config/gtk-3.0 ln -s ~/.dotfiles/gtk/gtk-4.0 ~/.config/gtk-4.0 # Miscellaneous ln -s ~/.dotfiles/misc/dunst ~/.config/dunst -ln -s ~/.dotfiles/misc/rofi ~/.config/rofi ln -s ~/.dotfiles/misc/zathura ~/.config/zathura ln -s ~/.dotfiles/misc/termite/ ~/.config/termite ln -s ~/.dotfiles/misc/systemd ~/.config/systemd @@ -29,6 +29,7 @@ ln -s ~/.dotfiles/tmux/tmux.conf ~/.tmux.conf # Xorg ln -s ~/.dotfiles/xorg/xinitrc ~/.xinitrc ln -s ~/.dotfiles/xorg/xmodmap ~/.xmodmap +ln -s ~/.dotfiles/xorg/Xresources ~/.Xresources # Zsh ln -s ~/.dotfiles/zsh/antibody ~/.config/antibody diff --git a/misc/rofi/config.rasi b/misc/rofi/config.rasi deleted file mode 100644 index 52af15b4..00000000 --- a/misc/rofi/config.rasi +++ /dev/null @@ -1,149 +0,0 @@ -configuration { -modi: "window,run,ssh,drun"; -/* width: 50;*/ -lines: 15; -/* columns: 1;*/ -font: "Cascadia Code 12"; -/* bw: 1;*/ -/* location: 0;*/ -/* padding: 5;*/ -/* yoffset: 0;*/ -/* xoffset: 0;*/ -/* fixed-num-lines: true;*/ -/* show-icons: false;*/ -/* terminal: "rofi-sensible-terminal";*/ -/* ssh-client: "ssh";*/ -/* ssh-command: "{terminal} -e {ssh-client} {host} [-p {port}]";*/ -/* run-command: "{cmd}";*/ -/* run-list-command: "";*/ -/* run-shell-command: "{terminal} -e {cmd}";*/ -/* window-command: "wmctrl -i -R {window}";*/ -/* window-match-fields: "all";*/ -/* icon-theme: ;*/ -/* drun-match-fields: "name,generic,exec,categories";*/ -/* drun-show-actions: false;*/ -/* drun-display-format: "{name} [({generic})]";*/ -/* disable-history: false;*/ -/* ignored-prefixes: "";*/ -/* sort: false;*/ -/* sorting-method: ;*/ -/* case-sensitive: false;*/ -/* cycle: true;*/ -/* sidebar-mode: false;*/ -/* eh: 1;*/ -/* auto-select: false;*/ -/* parse-hosts: false;*/ -/* parse-known-hosts: true;*/ -/* combi-modi: "window,run";*/ -/* matching: "normal";*/ -/* tokenize: true;*/ -/* m: "-5";*/ -/* line-margin: 2;*/ -/* line-padding: 1;*/ -/* filter: ;*/ -/* separator-style: "dash";*/ -/* hide-scrollbar: false;*/ -/* fullscreen: false;*/ -/* fake-transparency: false;*/ -/* dpi: -1;*/ -/* threads: 0;*/ -/* scrollbar-width: 8;*/ -/* scroll-method: 0;*/ -/* fake-background: "screenshot";*/ -/* window-format: "{w} {c} {t}";*/ -/* click-to-exit: true;*/ -/* show-match: true;*/ -/* theme: ;*/ -/* color-normal: ;*/ -/* color-urgent: ;*/ -/* color-active: ;*/ -/* color-window: ;*/ -/* max-history-size: 25;*/ -/* combi-hide-mode-prefix: false;*/ -/* matching-negate-char: '-' /* unsupported */;*/ -/* cache-dir: ;*/ -/* pid: "/run/user/1000/rofi.pid";*/ -/* display-window: ;*/ -/* display-windowcd: ;*/ -/* display-run: ;*/ -/* display-ssh: ;*/ -/* display-drun: ;*/ -/* display-combi: ;*/ -/* display-keys: ;*/ -/* kb-primary-paste: "Control+V,Shift+Insert";*/ -/* kb-secondary-paste: "Control+v,Insert";*/ -/* kb-clear-line: "Control+w";*/ -/* kb-move-front: "Control+a";*/ -/* kb-move-end: "Control+e";*/ -/* kb-move-word-back: "Alt+b,Control+Left";*/ -/* kb-move-word-forward: "Alt+f,Control+Right";*/ -/* kb-move-char-back: "Left,Control+b";*/ -/* kb-move-char-forward: "Right,Control+f";*/ -/* kb-remove-word-back: "Control+Alt+h,Control+BackSpace";*/ -/* kb-remove-word-forward: "Control+Alt+d";*/ -/* kb-remove-char-forward: "Delete,Control+d";*/ -/* kb-remove-char-back: "BackSpace,Shift+BackSpace,Control+h";*/ -/* kb-remove-to-eol: "Control+k";*/ -/* kb-remove-to-sol: "Control+u";*/ -/* kb-accept-entry: "Control+j,Control+m,Return,KP_Enter";*/ -/* kb-accept-custom: "Control+Return";*/ -/* kb-accept-alt: "Shift+Return";*/ -/* kb-delete-entry: "Shift+Delete";*/ -/* kb-mode-next: "Shift+Right,Control+Tab";*/ -/* kb-mode-previous: "Shift+Left,Control+ISO_Left_Tab";*/ -/* kb-row-left: "Control+Page_Up";*/ -/* kb-row-right: "Control+Page_Down";*/ -/* kb-row-up: "Up,Control+p,ISO_Left_Tab";*/ -/* kb-row-down: "Down,Control+n";*/ -/* kb-row-tab: "Tab";*/ -/* kb-page-prev: "Page_Up";*/ -/* kb-page-next: "Page_Down";*/ -/* kb-row-first: "Home,KP_Home";*/ -/* kb-row-last: "End,KP_End";*/ -/* kb-row-select: "Control+space";*/ -/* kb-screenshot: "Alt+S";*/ -/* kb-ellipsize: "Alt+period";*/ -/* kb-toggle-case-sensitivity: "grave,dead_grave";*/ -/* kb-toggle-sort: "Alt+grave";*/ -/* kb-cancel: "Escape,Control+g,Control+bracketleft";*/ -/* kb-custom-1: "Alt+1";*/ -/* kb-custom-2: "Alt+2";*/ -/* kb-custom-3: "Alt+3";*/ -/* kb-custom-4: "Alt+4";*/ -/* kb-custom-5: "Alt+5";*/ -/* kb-custom-6: "Alt+6";*/ -/* kb-custom-7: "Alt+7";*/ -/* kb-custom-8: "Alt+8";*/ -/* kb-custom-9: "Alt+9";*/ -/* kb-custom-10: "Alt+0";*/ -/* kb-custom-11: "Alt+exclam";*/ -/* kb-custom-12: "Alt+at";*/ -/* kb-custom-13: "Alt+numbersign";*/ -/* kb-custom-14: "Alt+dollar";*/ -/* kb-custom-15: "Alt+percent";*/ -/* kb-custom-16: "Alt+dead_circumflex";*/ -/* kb-custom-17: "Alt+ampersand";*/ -/* kb-custom-18: "Alt+asterisk";*/ -/* kb-custom-19: "Alt+parenleft";*/ -/* kb-select-1: "Super+1";*/ -/* kb-select-2: "Super+2";*/ -/* kb-select-3: "Super+3";*/ -/* kb-select-4: "Super+4";*/ -/* kb-select-5: "Super+5";*/ -/* kb-select-6: "Super+6";*/ -/* kb-select-7: "Super+7";*/ -/* kb-select-8: "Super+8";*/ -/* kb-select-9: "Super+9";*/ -/* kb-select-10: "Super+0";*/ -/* ml-row-left: "ScrollLeft";*/ -/* ml-row-right: "ScrollRight";*/ -/* ml-row-up: "ScrollUp";*/ -/* ml-row-down: "ScrollDown";*/ -/* me-select-entry: "MousePrimary";*/ -/* me-accept-entry: "MouseDPrimary";*/ -/* me-accept-custom: "Control+MouseDPrimary";*/ -} -@import "/home/yigit/.config/rofi/themes/dmenu.rasi" - - -/* vim:ft=css diff --git a/misc/rofi/music_menu b/misc/rofi/music_menu deleted file mode 100755 index 43bc6a17..00000000 --- a/misc/rofi/music_menu +++ /dev/null @@ -1,10 +0,0 @@ -action=$(echo ' -' | rofi -dmenu -theme music_actions ) - -if [ $action = '' ] -then - playerctl previous & -elif [ $action = '' ] -then - playerctl next & -fi diff --git a/misc/rofi/sidebar-mod.rasi b/misc/rofi/sidebar-mod.rasi deleted file mode 100644 index cbae1d6c..00000000 --- a/misc/rofi/sidebar-mod.rasi +++ /dev/null @@ -1,109 +0,0 @@ -/** - * User: qball - * Copyright: Dave Davenport - */ -* { - text-color: #f4f2f0; - background-color: rgba(0,0,0,0); - dark: #2c2541; - // Black - black: #3d335c; - lightblack: #483c6c; - // - // Red - red: #cd5c5c; - lightred: #cc5533; - // - // Green - green: #86af80; - lightgreen: #88cc22; - // - // Yellow - yellow: #e8ae5b; - lightyellow: #ffa75d; - // - // Blue - blue: #6495ed; - lightblue: #87ceeb; - // - // Magenta - magenta: #deb887; - lightmagenta: #996600; - // - // Cyan - cyan: #b0c4de; - lightcyan: #b0c4de; - // - // White - white: #bbaa99; - lightwhite: #ddccbb; - // - // Bold, Italic, Underline - highlight: bold #ffffff; -} -#window { - height: 50%; - width: 15em; - location: north east; - anchor: north east; - border: 0px 0px 0px 0px; - x-offset: -30px; - y-offset: 39px; - text-color: @lightwhite; - border-radius: 0px 0px 19px 19px; -} - -#mode-switcher { - border: 2px 0px 0px 0px; - background-color: @lightblack; - padding: 4px; -} -#button selected { - border-color: @lightgreen; - text-color: @lightgreen; -} -#inputbar { - background-color: #2c2541; - text-color: @lightgreen; - padding: 4px 4px 4px 4px; - border: 0px 0px 0px 0px; -} -#mainbox { - expand: true; - background-color: #1c1c1cee; - spacing: 1em; -} -#listview { - padding: 0em 1em 0em 1em; - dynamic: false; - lines: 0; -} - -#prompt { -margin: 0px 6px 0px 0px; -} -#element selected normal { - background-color: #da0f7a; -} -#element normal active { - text-color: @lightblue; -} -#element normal urgent { - text-color: @lightred; -} -#element alternate normal { -} -#element alternate active { - text-color: @lightblue; -} -#element alternate urgent { - text-color: @lightred; -} -#element selected active { - background-color: @lightblue; - text-color: @dark; -} -#element selected urgent { - background-color: @lightred; - text-color: @dark; -} diff --git a/misc/rofi/themes/denvit.rasi b/misc/rofi/themes/denvit.rasi deleted file mode 100644 index 72843d86..00000000 --- a/misc/rofi/themes/denvit.rasi +++ /dev/null @@ -1,149 +0,0 @@ -/* vim:ft=css */ -/************************************************ - * ROFI Color theme - * User: leofa - * Copyright: 2017 leofa - ***********************************************/ - -* { - selected-normal-foreground: rgba ( 249, 249, 249, 100 % ); - foreground: rgba ( 248, 248, 242, 100 % ); - normal-foreground: @foreground; - alternate-normal-background: rgba ( 35, 49, 63, 95%); - red: rgba ( 189, 147, 249, 100 % ); - selected-urgent-foreground: rgba ( 249, 249, 249, 100 % ); - blue: rgba ( 38, 139, 210, 100 % ); - urgent-foreground: rgba ( 204, 102, 102, 100 % ); - alternate-urgent-background: rgba ( 75, 81, 96, 90 % ); - active-foreground: rgba ( 101, 172, 255, 100 % ); - lightbg: rgba ( 238, 232, 213, 100 % ); - selected-active-foreground: rgba ( 249, 249, 249, 100 % ); - alternate-active-background: rgba ( 52,73,94, 60%); - background: rgba ( 189, 147, 249, 95 % ); - alternate-normal-foreground: @foreground; - normal-background: @background; - - lightfg: rgba ( 88, 104, 117, 100 % ); - selected-normal-background: rgba ( 189, 147, 249, 100 % ); - border-color: rgba ( 124, 131, 137, 100 % ); - spacing: 2; - separatorcolor: rgba ( 29, 31, 33, 100 % ); - urgent-background: rgba ( 29, 31, 33, 17 % ); - selected-urgent-background: rgba ( 189, 147, 249, 100 % ); - alternate-urgent-foreground: @urgent-foreground; - background-color: rgba ( 0, 0, 0, 0 % ); - alternate-active-foreground: @active-foreground; - active-background: rgba ( 29, 31, 33, 17 % ); - selected-active-background: rgba ( 189, 147, 249, 100 % ); -} -#window { - background-color: @background; - border: 1; - padding: 5; -} -#mainbox { - border: 0; - padding: 0; -} -#message { - border: 2px 0px 0px ; - border-color: @separatorcolor; - padding: 1px ; -} -#textbox { - text-color: @foreground; -} -#listview { - fixed-height: 0; - border: 0px 0px 0px ; - border-color: @separatorcolor; - spacing: 2px ; - scrollbar: true; - padding: 2px 0px 0px ; -} -#element { - border: 0; - padding: 1px; -} -#element.normal.normal { - background-color: @normal-background; - text-color: @normal-foreground; -} -#element.normal.urgent { - background-color: @urgent-background; - text-color: @urgent-foreground; -} -#element.normal.active { - background-color: @active-background; - text-color: @active-foreground; -} -#element.selected.normal { - background-color: @selected-normal-background; - text-color: @selected-normal-foreground; -} -#element.selected.urgent { - background-color: @selected-urgent-background; - text-color: @selected-urgent-foreground; -} -#element.selected.active { - background-color: @selected-active-background; - text-color: @selected-active-foreground; -} -#element.alternate.normal { - background-color: @alternate-normal-background; - text-color: @alternate-normal-foreground; -} -#element.alternate.urgent { - background-color: @alternate-urgent-background; - text-color: @alternate-urgent-foreground; -} -#element.alternate.active { - background-color: @alternate-active-background; - text-color: @alternate-active-foreground; -} -#scrollbar { - width: 4px ; - border: 0; - handle-color: @normal-foreground; - handle-width: 8px ; - padding: 0; -} -#sidebar { - border: 0px 0px 0px; - padding: 5px 0 0; - border-color: @separatorcolor; -} -#button { - spacing: 0; - text-color: @normal-foreground; -} -#button.selected { - background-color: @selected-normal-background; - text-color: @selected-normal-foreground; -} -#inputbar { - spacing: 0; - text-color: @normal-foreground; - padding: 1px ; -} -#case-indicator { - spacing: 0; - text-color: @normal-foreground; -} -#entry { - spacing: 0; - text-color: @normal-foreground; -} -#prompt { - spacing: 0; - text-color: @normal-foreground; -} -#inputbar { - children: [ prompt,textbox-prompt-colon,entry,case-indicator ]; -} -#textbox-prompt-colon { - expand: false; - str: ":"; - margin: 0px 0.3em 0em 0em ; - text-color: @normal-foreground; -} diff --git a/misc/rofi/themes/dmenu.rasi b/misc/rofi/themes/dmenu.rasi deleted file mode 100644 index ffa214ca..00000000 --- a/misc/rofi/themes/dmenu.rasi +++ /dev/null @@ -1,44 +0,0 @@ -/** - * ROFI Color theme - * User: Qball - * Copyright: Dave Davenport - */ -* { - background-color: rgba(40, 42, 54, 1); - border-color: rgba(248, 248, 242, 1); - text-color: rgba(248, 248, 242, 1); - font: "Hack Nerd Font 10"; -} - -window { - anchor: north; - location: north; - width: 100%; - padding: 6px; - children: [ horibox ]; -} - -horibox { - orientation: horizontal; - children: [ prompt, entry, listview ]; -} - -listview { - layout: horizontal; - spacing: 5px; - lines: 100; -} - -entry { - expand: false; - width: 10em; -} - -element { - padding: 0px 2px; -} -element selected { - background-color: rgba(189, 147, 249, 1); -} - -/* vim:ft=css diff --git a/scripts/dmenu-bluetooth b/scripts/dmenu-bluetooth new file mode 100755 index 00000000..5b796dbb --- /dev/null +++ b/scripts/dmenu-bluetooth @@ -0,0 +1,290 @@ +#!/usr/bin/env bash +# _ _ _ _ _ _ +# __| |_ __ ___ ___ _ __ _ _ | |__ | |_ _ ___| |_ ___ ___ | |_ | |__ +# / _` | '_ ` _ \ / _ \ '_ \| | | |_____| '_ \| | | | |/ _ \ __/ _ \ / _ \| __|| '_ \ +# | (_| | | | | | | __/ | | | |_| |_____| |_) | | |_| | __/ || (_) | (_) | |_ | | | | +# \__,_|_| |_| |_|\___|_| |_|\__,_| |_.__/|_|\__,_|\___|\__\___/ \___/ \__||_| |_| +# +# Author: Nick Clyde (clydedroid) +# dmenu support by: Layerex +# +# A script that generates a dmenu menu that uses bluetoothctl to +# connect to bluetooth devices and display status info. +# +# Inspired by networkmanager-dmenu (https://github.com/firecat53/networkmanager-dmenu) +# Thanks to x70b1 (https://github.com/polybar/polybar-scripts/tree/master/polybar-scripts/system-bluetooth-bluetoothctl) +# +# Depends on: +# Arch repositories: dmenu, bluez-utils (contains bluetoothctl) + +# Checks if bluetooth controller is powered on +power_on() { + if bluetoothctl show | grep -q "Powered: yes"; then + return 0 + else + return 1 + fi +} + +# Toggles power state +toggle_power() { + if power_on; then + bluetoothctl power off + else + bluetoothctl power on + fi +} + +# Checks if controller is scanning for new devices +scan_on() { + if bluetoothctl show | grep -q "Discovering: yes"; then + echo "Scan: on" + return 0 + else + echo "Scan: off" + return 1 + fi +} + +# Toggles scanning state +toggle_scan() { + if scan_on; then + kill $(pgrep -f "bluetoothctl scan on") + bluetoothctl scan off + else + bluetoothctl scan on & + fi +} + +# Checks if controller is able to pair to devices +pairable_on() { + if bluetoothctl show | grep -q "Pairable: yes"; then + echo "Pairable: on" + return 0 + else + echo "Pairable: off" + return 1 + fi +} + +# Toggles pairable state +toggle_pairable() { + if pairable_on; then + bluetoothctl pairable off + else + bluetoothctl pairable on + fi +} + +# Checks if controller is discoverable by other devices +discoverable_on() { + if bluetoothctl show | grep -q "Discoverable: yes"; then + echo "Discoverable: on" + return 0 + else + echo "Discoverable: off" + return 1 + fi +} + +# Toggles discoverable state +toggle_discoverable() { + if discoverable_on; then + bluetoothctl discoverable off + else + bluetoothctl discoverable on + fi +} + +# Checks if a device is connected +device_connected() { + device_info=$(bluetoothctl info "$1") + if echo "$device_info" | grep -q "Connected: yes"; then + return 0 + else + return 1 + fi +} + +# Toggles device connection +toggle_connection() { + if device_connected $1; then + bluetoothctl disconnect $1 + else + bluetoothctl connect $1 + fi +} + +# Checks if a device is paired +device_paired() { + device_info=$(bluetoothctl info "$1") + if echo "$device_info" | grep -q "Paired: yes"; then + echo "Paired: yes" + return 0 + else + echo "Paired: no" + return 1 + fi +} + +# Toggles device paired state +toggle_paired() { + if device_paired $1; then + bluetoothctl remove $1 + else + bluetoothctl pair $1 + fi +} + +# Checks if a device is trusted +device_trusted() { + device_info=$(bluetoothctl info "$1") + if echo "$device_info" | grep -q "Trusted: yes"; then + echo "Trusted: yes" + return 0 + else + echo "Trusted: no" + return 1 + fi +} + +# Toggles device connection +toggle_trust() { + if device_trusted $1; then + bluetoothctl untrust $1 + else + bluetoothctl trust $1 + fi +} + +# Prints a short string with the current bluetooth status +# Useful for status bars like polybar, etc. +print_status() { + if power_on; then + printf '' + + mapfile -t paired_devices < <(bluetoothctl paired-devices | grep Device | cut -d ' ' -f 2) + counter=0 + + for device in "${paired_devices[@]}"; do + if device_connected $device; then + device_alias=$(bluetoothctl info $device | grep "Alias" | cut -d ' ' -f 2-) + + if [ $counter -gt 0 ]; then + printf ", %s" "$device_alias" + else + printf " %s" "$device_alias" + fi + + ((counter++)) + fi + done + + if [ $counter -eq 0 ]; then + printf " On" + fi + else + echo " Off" + fi +} + +# A submenu for a specific device that allows connecting, pairing, and trusting +device_menu() { + device=$1 + + # Get device name and mac address + device_name=$(echo $device | cut -d ' ' -f 3-) + mac=$(echo $device | cut -d ' ' -f 2) + + # Build options + if device_connected $mac; then + connected="Connected: yes" + else + connected="Connected: no" + fi + paired=$(device_paired $mac) + trusted=$(device_trusted $mac) + options="$connected\n$paired\n$trusted" + + # Open dmenu menu, read chosen option + chosen="$(echo -e "$options" | $dmenu_command "$device_name")" + + # Match chosen option to command + case $chosen in + "") + echo "No option chosen." + ;; + $connected) + toggle_connection $mac + ;; + $paired) + toggle_paired $mac + ;; + $trusted) + toggle_trust $mac + ;; + esac +} + +# Opens a dmenu menu with current bluetooth status and options to connect +show_menu() { + # Get menu options + if power_on; then + power="Power: on" + + # Human-readable names of devices, one per line + # If scan is off, will only list paired devices + devices=$(bluetoothctl devices | grep Device | cut -d ' ' -f 3-) + + # Get controller flags + scan=$(scan_on) + pairable=$(pairable_on) + discoverable=$(discoverable_on) + divider="---------" + + # Options passed to dmenu + options="$devices\n$divider\n$power\n$scan\n$pairable\n$discoverable" + else + power="Power: off" + options="$power" + fi + + # Open dmenu menu, read chosen option + chosen="$(echo -e "$options" | $dmenu_command "Bluetooth")" + + # Match chosen option to command + case $chosen in + "" | $divider) + echo "No option chosen." + ;; + $power) + toggle_power + ;; + $scan) + toggle_scan + ;; + $discoverable) + toggle_discoverable + ;; + $pairable) + toggle_pairable + ;; + *) + device=$(bluetoothctl devices | grep "$chosen") + # Open a submenu if a device is selected + if [[ $device ]]; then device_menu "$device"; fi + ;; + esac +} + +# dmenu command to pipe into, can add any options here +dmenu_command="dmenu -z 1900 -x 10 -y 10 -i -p" + +case "$1" in + --status) + print_status + ;; + *) + show_menu + ;; +esac diff --git a/scripts/dmenu-logout b/scripts/dmenu-logout index b44d21da..52649b84 100755 --- a/scripts/dmenu-logout +++ b/scripts/dmenu-logout @@ -26,7 +26,7 @@ logout() { # Load dmenu config # shellcheck source=/dev/null -[ -f "$HOME/.dmenurc" ] && . "$HOME/.dmenurc" || DMENU='dmenu -i' +[ -f "$HOME/.dmenurc" ] && . "$HOME/.dmenurc" || DMENU='dmenu -z 1900 -x 10 -y 10 -i' # Menu items items="logout diff --git a/scripts/edit_screen.sh b/scripts/edit_screen.sh new file mode 100755 index 00000000..33266668 --- /dev/null +++ b/scripts/edit_screen.sh @@ -0,0 +1,5 @@ +#!/bin/sh +tmpfile=$(mktemp /tmp/st-edit.XXXXXX) +trap 'rm "$tmpfile"' 0 1 15 +cat > "$tmpfile" +st -e "$EDITOR" "$tmpfile" diff --git a/scripts/layoutmenu.sh b/scripts/layoutmenu.sh new file mode 100755 index 00000000..1bf95f23 --- /dev/null +++ b/scripts/layoutmenu.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +cat <<> Floating Layout 1 +[M] Monocle Layout 2 +EOF diff --git a/scripts/networkmanager_dmenu b/scripts/networkmanager_dmenu new file mode 100755 index 00000000..34547eb4 --- /dev/null +++ b/scripts/networkmanager_dmenu @@ -0,0 +1,874 @@ +#!/usr/bin/env python3 +# encoding:utf8 +"""NetworkManager command line dmenu script. + +To add new connections or enable/disable networking requires policykit +permissions setup per: +https://wiki.archlinux.org/index.php/NetworkManager#Set_up_PolicyKit_permissions + +OR running the script as root + +Add dmenu formatting options and default terminal if desired to +~/.config/networkmanager-dmenu/config.ini + +""" +import pathlib +import struct +import configparser +import itertools +import locale +import os +from os.path import expanduser +import shlex +import sys +import uuid +from subprocess import Popen, PIPE + +import gi +gi.require_version('NM', '1.0') +from gi.repository import GLib, NM # pylint: disable=wrong-import-position + +ENV = os.environ.copy() +ENV['LC_ALL'] = 'C' +ENC = locale.getpreferredencoding() + +CLIENT = NM.Client.new(None) +LOOP = GLib.MainLoop() +CONNS = CLIENT.get_connections() + +CONF = configparser.ConfigParser() +CONF.read(expanduser("~/.config/networkmanager-dmenu/config.ini")) + +def dmenu_cmd(num_lines, prompt="Networks", active_lines=None): # pylint: disable=too-many-branches + """Parse config.ini if it exists and add options to the dmenu command + + Args: args - num_lines: number of lines to display + prompt: prompt to show + Returns: command invocation (as a list of strings) for + dmenu -l -p -i ... + + """ + dmenu_command = "dmenu" + if not CONF.sections(): + res = [dmenu_command, "-z", "1900", "-x", "10", "-y", "10", "-i", "-l", str(num_lines), "-p", str(prompt)] + res.extend(sys.argv[1:]) + return res + if CONF.has_section('dmenu'): + args = CONF.items('dmenu') + args_dict = dict(args) + dmenu_args = [] + if "dmenu_command" in args_dict: + command = shlex.split(args_dict["dmenu_command"]) + dmenu_command = command[0] + dmenu_args = command[1:] + del args_dict["dmenu_command"] + if "p" in args_dict and prompt == "Networks": + prompt = args_dict["p"] + del args_dict["p"] + elif "p" in args_dict: + del args_dict["p"] + if "rofi" in dmenu_command: + lines = "-i -dmenu -lines" + # rofi doesn't support 0 length line, it requires at least -lines=1 + # see https://github.com/DaveDavenport/rofi/issues/252 + num_lines = num_lines or 1 + else: + lines = "-i -l" + if "l" in args_dict: + # rofi doesn't support 0 length line, it requires at least -lines=1 + # see https://github.com/DaveDavenport/rofi/issues/252 + if "rofi" in dmenu_command: + args_dict['l'] = min(num_lines, int(args_dict['l'])) or 1 + lines = "{} {}".format(lines, args_dict['l']) + del args_dict['l'] + else: + lines = "{} {}".format(lines, num_lines) + if "pinentry" in args_dict: + del args_dict["pinentry"] + if "compact" in args_dict: + del args_dict["compact"] + if "wifi_chars" in args_dict: + del args_dict["wifi_chars"] + rofi_highlight = CONF.getboolean('dmenu', 'rofi_highlight', fallback=False) + if CONF.has_option('dmenu', 'rofi_highlight'): + del args_dict["rofi_highlight"] + if rofi_highlight is True and "rofi" in dmenu_command: + if active_lines: + dmenu_args.extend(["-a", ",".join([str(num) + for num in active_lines])]) + if prompt == "Passphrase": + if CONF.has_section('dmenu_passphrase'): + args = CONF.items('dmenu_passphrase') + args_dict.update(args) + rofi_obscure = CONF.getboolean('dmenu_passphrase', 'rofi_obscure', fallback=True) + if CONF.has_option('dmenu_passphrase', 'rofi_obscure'): + del args_dict["rofi_obscure"] + if rofi_obscure is True and "rofi" in dmenu_command: + dmenu_args.extend(["-password"]) + dmenu_password = CONF.getboolean('dmenu_passphrase', 'dmenu_password', fallback=False) + if CONF.has_option('dmenu_passphrase', 'dmenu_password'): + del args_dict["dmenu_password"] + if dmenu_password is True: + dmenu_args.extend(["-P"]) + extras = (["-" + str(k), str(v)] for (k, v) in args_dict.items()) + res = [dmenu_command, "-p", str(prompt)] + res.extend(dmenu_args) + res += list(itertools.chain.from_iterable(extras)) + res[1:1] = lines.split() + res = list(filter(None, res)) # Remove empty list elements + res.extend(sys.argv[1:]) + return res + + +def choose_adapter(client): + """If there is more than one wifi adapter installed, ask which one to use + + """ + devices = client.get_devices() + devices = [i for i in devices if i.get_device_type() == NM.DeviceType.WIFI] + if not devices: # pylint: disable=no-else-return + return None + elif len(devices) == 1: + return devices[0] + device_names = "\n".join([d.get_iface() for d in devices]).encode(ENC) + sel = Popen(dmenu_cmd(len(devices), "CHOOSE ADAPTER:"), + stdin=PIPE, + stdout=PIPE, + env=ENV).communicate(input=device_names)[0].decode(ENC) + if not sel.strip(): + sys.exit() + devices = [i for i in devices if i.get_iface() == sel.strip()] + assert len(devices) == 1 + return devices[0] + + +def is_modemmanager_installed(): + """Check if ModemManager is installed""" + with open(os.devnull) as devnull: + try: + Popen(["ModemManager"], stdout=devnull, stderr=devnull).communicate() + except OSError: + return False + return True + + +def bluetooth_get_enabled(): + """Check if bluetooth is enabled via rfkill. + + Returns None if no bluetooth device was found. + """ + # See https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-class-rfkill + for path in pathlib.Path('/sys/class/rfkill/').glob('rfkill*'): + if (path / 'type').read_text().strip() == 'bluetooth': + return (path / 'soft').read_text().strip() == '0' + return None + + +def create_other_actions(client): + """Return list of other actions that can be taken + + """ + networking_enabled = client.networking_get_enabled() + networking_action = "Disable" if networking_enabled else "Enable" + + wifi_enabled = client.wireless_get_enabled() + wifi_action = "Disable" if wifi_enabled else "Enable" + + bluetooth_enabled = bluetooth_get_enabled() + bluetooth_action = "Disable" if bluetooth_enabled else "Enable" + + actions = [Action("{} Wifi".format(wifi_action), toggle_wifi, + not wifi_enabled), + Action("{} Networking".format(networking_action), + toggle_networking, not networking_enabled)] + if bluetooth_enabled is not None: + actions.append(Action("{} Bluetooth".format(bluetooth_action), + toggle_bluetooth, not bluetooth_enabled)) + actions += [Action("Launch Connection Manager", launch_connection_editor), + Action("Delete a Connection", delete_connection)] + if wifi_enabled: + actions.append(Action("Rescan Wifi Networks", rescan_wifi)) + return actions + + +def rescan_wifi(): + """ + Rescan Wifi Access Points + """ + for dev in CLIENT.get_devices(): + if gi.repository.NM.DeviceWifi == type(dev): + try: + dev.request_scan_async(None, rescan_cb, None) + LOOP.run() + except gi.repository.GLib.Error as err: + # Too frequent rescan error + notify("Wifi rescan failed", urgency="critical") + if not err.code == 6: # pylint: disable=no-member + raise err + + +def rescan_cb(dev, res, data): + """Callback for rescan_wifi. Just for notifications + + """ + if dev.request_scan_finish(res) is True: + notify("Wifi scan complete") + else: + notify("Wifi scan failed", urgency="critical") + LOOP.quit() + + +def ssid_to_utf8(nm_ap): + """ Convert binary ssid to utf-8 """ + ssid = nm_ap.get_ssid() + if not ssid: + return "" + ret = NM.utils_ssid_to_utf8(ssid.get_data()) + return ret + + +def prompt_saved(saved_cons): + """Prompt for a saved connection.""" + actions = create_saved_actions(saved_cons) + sel = get_selection(actions) + sel() + + +def ap_security(nm_ap): + """Parse the security flags to return a string with 'WPA2', etc. """ + flags = nm_ap.get_flags() + wpa_flags = nm_ap.get_wpa_flags() + rsn_flags = nm_ap.get_rsn_flags() + sec_str = "" + if ((flags & getattr(NM, '80211ApFlags').PRIVACY) and + (wpa_flags == 0) and (rsn_flags == 0)): + sec_str += " WEP" + if wpa_flags != 0: + sec_str += " WPA1" + if rsn_flags != 0: + sec_str += " WPA2" + if ((wpa_flags & getattr(NM, '80211ApSecurityFlags').KEY_MGMT_802_1X) or + (rsn_flags & getattr(NM, '80211ApSecurityFlags').KEY_MGMT_802_1X)): + sec_str += " 802.1X" + + # If there is no security use "--" + if sec_str == "": + sec_str = "--" + return sec_str.lstrip() + + +class Action(): # pylint: disable=too-few-public-methods + """Helper class to execute functions from a string variable""" + def __init__(self, + name, + func, + args=None, + active=False): + self.name = name + self.func = func + self.is_active = active + if args is None: + self.args = None + elif isinstance(args, list): + self.args = args + else: + self.args = [args] + + def __str__(self): + return self.name + + def __call__(self): + if self.args is None: + self.func() + else: + self.func(*self.args) + + +def process_ap(nm_ap, is_active, adapter): + """Activate/Deactivate a connection and get password if required""" + if is_active: + CLIENT.deactivate_connection_async(nm_ap, None, deactivate_cb, nm_ap) + else: + conns_cur = [i for i in CONNS if + i.get_setting_wireless() is not None and + i.get_setting_wireless().get_mac_address() == + adapter.get_permanent_hw_address()] + con = nm_ap.filter_connections(conns_cur) + if len(con) > 1: + raise ValueError("There are multiple connections possible") + + if len(con) == 1: + CLIENT.activate_connection_async(con[0], adapter, nm_ap.get_path(), + None, activate_cb, nm_ap) + else: + if ap_security(nm_ap) != "--": + password = get_passphrase() + else: + password = "" + set_new_connection(nm_ap, password, adapter) + LOOP.run() + + +def activate_cb(dev, res, data): + """Notification if activate connection completed successfully + + """ + try: + conn = dev.activate_connection_finish(res) + except GLib.Error: + conn = None + if conn is not None: + notify("Activated {}".format(conn.get_id())) + else: + notify("Problem activating {}".format(data.get_id()), + urgency="critical") + LOOP.quit() + + +def deactivate_cb(dev, res, data): + """Notification if deactivate connection completed successfully + + """ + if dev.deactivate_connection_finish(res) is True: + notify("Deactivated {}".format(data.get_id())) + else: + notify("Problem deactivating {}".format(data.get_id()), + urgency="critical") + LOOP.quit() + + +def process_vpngsm(con, activate): + """Activate/deactive VPN or GSM connections""" + if activate: + CLIENT.activate_connection_async(con, None, None, + None, activate_cb, con) + else: + CLIENT.deactivate_connection_async(con, None, deactivate_cb, con) + LOOP.run() + + +def create_ap_actions(aps, active_ap, active_connection, adapter): # pylint: disable=too-many-locals + """For each AP in a list, create the string and its attached function + (activate/deactivate) + + """ + active_ap_bssid = active_ap.get_bssid() if active_ap is not None else "" + + names = [ssid_to_utf8(ap) for ap in aps] + max_len_name = max([len(name) for name in names]) if names else 0 + secs = [ap_security(ap) for ap in aps] + max_len_sec = max([len(sec) for sec in secs]) if secs else 0 + + ap_actions = [] + + for nm_ap, name, sec in zip(aps, names, secs): + bars = NM.utils_wifi_strength_bars(nm_ap.get_strength()) + wifi_chars = CONF.get("dmenu", "wifi_chars", fallback=False) + if wifi_chars: + bars = "".join([wifi_chars[i] for i, j in enumerate(bars) if j == '*']) + is_active = nm_ap.get_bssid() == active_ap_bssid + compact = CONF.getboolean("dmenu", "compact", fallback=False) + if compact: + action_name = u"{} {} {}".format(name, sec, bars) + else: + action_name = u"{:<{}s} {:<{}s} {}".format(name, max_len_name, sec, + max_len_sec, bars) + if is_active: + ap_actions.append(Action(action_name, process_ap, + [active_connection, True, adapter], + active=True)) + else: + ap_actions.append(Action(action_name, process_ap, + [nm_ap, False, adapter])) + return ap_actions + + +def create_vpn_actions(vpns, active): + """Create the list of strings to display with associated function + (activate/deactivate) for VPN connections. + + """ + active_vpns = [i for i in active if i.get_vpn()] + return _create_vpngsm_actions(vpns, active_vpns, "VPN") + + +def create_wireguard_actions(wgs, active): + """Create the list of strings to display with associated function + (activate/deactivate) for Wireguard connections. + + """ + active_wgs = [i for i in active if i.get_connection_type() == "wireguard"] + return _create_vpngsm_actions(wgs, active_wgs, "Wireguard") + + +def create_eth_actions(eths, active): + """Create the list of strings to display with associated function + (activate/deactivate) for Ethernet connections. + + """ + active_eths = [i for i in active if 'ethernet' in i.get_connection_type()] + return _create_vpngsm_actions(eths, active_eths, "Eth") + + +def create_gsm_actions(gsms, active): + """Create the list of strings to display with associated function + (activate/deactivate) GSM connections.""" + active_gsms = [i for i in active if + i.get_connection() is not None and + i.get_connection().is_type(NM.SETTING_GSM_SETTING_NAME)] + return _create_vpngsm_actions(gsms, active_gsms, "GSM") + + +def create_blue_actions(blues, active): + """Create the list of strings to display with associated function + (activate/deactivate) Bluetooth connections.""" + active_blues = [i for i in active if + i.get_connection() is not None and + i.get_connection().is_type(NM.SETTING_BLUETOOTH_SETTING_NAME)] + return _create_vpngsm_actions(blues, active_blues, "Bluetooth") + + +def create_saved_actions(saved): + """Create the list of strings to display with associated function + (activate/deactivate) for VPN connections. + + """ + return _create_vpngsm_actions(saved, [], "SAVED") + + +def _create_vpngsm_actions(cons, active_cons, label): + active_con_ids = [a.get_id() for a in active_cons] + actions = [] + for con in cons: + is_active = con.get_id() in active_con_ids + action_name = u"{}:{}".format(con.get_id(), label) + if is_active: + active_connection = [a for a in active_cons + if a.get_id() == con.get_id()] + if len(active_connection) != 1: + raise ValueError(u"Multiple active connections match" + " the connection: {}".format(con.get_id())) + active_connection = active_connection[0] + + actions.append(Action(action_name, process_vpngsm, + [active_connection, False], active=True)) + else: + actions.append(Action(action_name, process_vpngsm, + [con, True])) + return actions + + +def create_wwan_actions(client): + """Create WWWAN actions + + """ + wwan_enabled = client.wwan_get_enabled() + wwan_action = "Disable" if wwan_enabled else "Enable" + return [Action("{} WWAN".format(wwan_action), toggle_wwan, not wwan_enabled)] + + +def combine_actions(eths, aps, vpns, wgs, gsms, blues, wwan, others, saved): + """Combine all given actions into a list of actions. + + Args: args - eths: list of Actions + aps: list of Actions + vpns: list of Actions + gsms: list of Actions + blues: list of Actions + wwan: list of Actions + others: list of Actions + """ + compact = CONF.getboolean("dmenu", "compact", fallback=False) + empty_action = [Action('', None)] if not compact else [] + all_actions = [] + all_actions += eths + empty_action if eths else [] + all_actions += aps + empty_action if aps else [] + all_actions += vpns + empty_action if vpns else [] + all_actions += wgs + empty_action if wgs else [] + all_actions += gsms + empty_action if (gsms and wwan) else [] + all_actions += blues + empty_action if blues else [] + all_actions += wwan + empty_action if wwan else [] + all_actions += others + empty_action if others else [] + all_actions += saved + empty_action if saved else [] + return all_actions + + +def get_selection(all_actions): + """Spawn dmenu for selection and execute the associated action.""" + rofi_highlight = CONF.getboolean('dmenu', 'rofi_highlight', fallback=False) + inp = [] + + if rofi_highlight is True: + inp = [str(action) for action in all_actions] + else: + inp = [('== ' if action.is_active else ' ') + str(action) + for action in all_actions] + active_lines = [index for index, action in enumerate(all_actions) + if action.is_active] + + inp_bytes = "\n".join(inp).encode(ENC) + command = dmenu_cmd(len(inp), active_lines=active_lines) + sel = Popen(command, stdin=PIPE, stdout=PIPE, + env=ENV).communicate(input=inp_bytes)[0].decode(ENC) + + if not sel.rstrip(): + sys.exit() + + if rofi_highlight is False: + action = [i for i in all_actions + if ((str(i).strip() == str(sel.strip()) + and not i.is_active) or + ('== ' + str(i) == str(sel.rstrip('\n')) + and i.is_active))] + else: + action = [i for i in all_actions if str(i).strip() == sel.strip()] + assert len(action) == 1, \ + u"Selection was ambiguous: '{}'".format(str(sel.strip())) + return action[0] + + +def toggle_networking(enable): + """Enable/disable networking + + Args: enable - boolean + + """ + toggle = GLib.Variant.new_tuple(GLib.Variant.new_boolean(enable)) + try: + CLIENT.dbus_call(NM.DBUS_PATH, NM.DBUS_INTERFACE, "Enable", toggle, + None, -1, None, None, None) + except AttributeError: + # Workaround for older versions of python-gobject + CLIENT.networking_set_enabled(enable) + notify("Networking {}".format("enabled" if enable is True else "disabled")) + + +def toggle_wifi(enable): + """Enable/disable Wifi + + Args: enable - boolean + + """ + toggle = GLib.Variant.new_boolean(enable) + try: + CLIENT.dbus_set_property(NM.DBUS_PATH, NM.DBUS_INTERFACE, "WirelessEnabled", toggle, + -1, None, None, None) + except AttributeError: + # Workaround for older versions of python-gobject + CLIENT.wireless_set_enabled(enable) + notify("Wifi {}".format("enabled" if enable is True else "disabled")) + + +def toggle_wwan(enable): + """Enable/disable WWAN + + Args: enable - boolean + + """ + toggle = GLib.Variant.new_boolean(enable) + try: + CLIENT.dbus_set_property(NM.DBUS_PATH, NM.DBUS_INTERFACE, "WwanEnabled", toggle, + -1, None, None, None) + except AttributeError: + # Workaround for older versions of python-gobject + CLIENT.wwan_set_enabled(enable) + notify("Wwan {}".format("enabled" if enable is True else "disabled")) + + +def toggle_bluetooth(enable): + """Enable/disable Bluetooth + + Args: enable - boolean + + References: + https://github.com/blueman-project/blueman/blob/master/blueman/plugins/mechanism/RfKill.py + https://www.kernel.org/doc/html/latest/driver-api/rfkill.html + https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/uapi/linux/rfkill.h?h=v5.8.9 + + """ + type_bluetooth = 2 + op_change_all = 3 + idx = 0 + soft_state = 0 if enable else 1 + hard_state = 0 + + data = struct.pack("IBBBB", idx, type_bluetooth, op_change_all, + soft_state, hard_state) + + try: + with open('/dev/rfkill', 'r+b', buffering=0) as rff: + rff.write(data) + except PermissionError: + notify("Lacking permission to write to /dev/rfkill.", + "Maybe you need to add your user to the 'rfkill' group?", + urgency="critical") + else: + notify("Bluetooth {}".format("enabled" if enable else "disabled")) + + +def launch_connection_editor(): + """Launch nmtui or the gui nm-connection-editor + + """ + terminal = CONF.get("editor", "terminal", fallback="xterm") + gui_if_available = CONF.getboolean("editor", "gui_if_available", fallback=True) + if gui_if_available is True: + try: + Popen(["gnome-control-center", "network"]).communicate() + except OSError: + try: + Popen(["nm-connection-editor"]).communicate() + except OSError: + Popen([terminal, "-e", "nmtui"]).communicate() + else: + Popen([terminal, "-e", "nmtui"]).communicate() + + +def get_passphrase(): + """Get a password + + Returns: string + + """ + pinentry = CONF.get("dmenu", "pinentry", fallback=None) + if pinentry: + pin = "" + out = Popen(pinentry, + stdout=PIPE, + stdin=PIPE).communicate(input=b'setdesc Get network password\ngetpin\n')[0] + if out: + res = out.decode(ENC).split("\n")[2] + if res.startswith("D "): + pin = res.split("D ")[1] + return pin + return Popen(dmenu_cmd(0, "Passphrase"), + stdin=PIPE, stdout=PIPE).communicate()[0].decode(ENC) + + +def delete_connection(): + """Display list of NM connections and delete the selected one + + """ + conn_acts = [Action(i.get_id(), i.delete_async, args=[None, delete_cb, None]) for i in CONNS] + conn_names = "\n".join([str(i) for i in conn_acts]).encode(ENC) + sel = Popen(dmenu_cmd(len(conn_acts), "CHOOSE CONNECTION TO DELETE:"), + stdin=PIPE, + stdout=PIPE, + env=ENV).communicate(input=conn_names)[0].decode(ENC) + if not sel.strip(): + sys.exit() + action = [i for i in conn_acts if str(i) == sel.rstrip("\n")] + assert len(action) == 1, u"Selection was ambiguous: {}".format(str(sel)) + action[0]() + LOOP.run() + + +def delete_cb(dev, res, data): + """Notification if delete completed successfully + + """ + if dev.delete_finish(res) is True: + notify("Deleted {}".format(dev.get_id())) + else: + notify("Problem deleting {}".format(dev.get_id()), urgency="critical") + LOOP.quit() + + +def set_new_connection(nm_ap, nm_pw, adapter): + """Setup a new NetworkManager connection + + Args: ap - NM.AccessPoint + pw - string + + """ + nm_pw = str(nm_pw).strip() + profile = create_wifi_profile(nm_ap, nm_pw, adapter) + CLIENT.add_and_activate_connection_async(profile, adapter, nm_ap.get_path(), + None, verify_conn, profile) + LOOP.run() + + +def create_wifi_profile(nm_ap, password, adapter): + # pylint: disable=C0301 + # From https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/examples/python/gi/add_connection.py + # and https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/examples/python/dbus/add-wifi-psk-connection.py + # pylint: enable=C0301 + """Create the NM profile given the AP and passphrase""" + ap_sec = ap_security(nm_ap) + profile = NM.SimpleConnection.new() + + s_con = NM.SettingConnection.new() + s_con.set_property(NM.SETTING_CONNECTION_ID, ssid_to_utf8(nm_ap)) + s_con.set_property(NM.SETTING_CONNECTION_UUID, str(uuid.uuid4())) + s_con.set_property(NM.SETTING_CONNECTION_TYPE, "802-11-wireless") + profile.add_setting(s_con) + + s_wifi = NM.SettingWireless.new() + s_wifi.set_property(NM.SETTING_WIRELESS_SSID, nm_ap.get_ssid()) + s_wifi.set_property(NM.SETTING_WIRELESS_MODE, 'infrastructure') + s_wifi.set_property(NM.SETTING_WIRELESS_MAC_ADDRESS, adapter.get_permanent_hw_address()) + profile.add_setting(s_wifi) + + s_ip4 = NM.SettingIP4Config.new() + s_ip4.set_property(NM.SETTING_IP_CONFIG_METHOD, "auto") + profile.add_setting(s_ip4) + + s_ip6 = NM.SettingIP6Config.new() + s_ip6.set_property(NM.SETTING_IP_CONFIG_METHOD, "auto") + profile.add_setting(s_ip6) + + if ap_sec != "--": + s_wifi_sec = NM.SettingWirelessSecurity.new() + if "WPA" in ap_sec: + s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_KEY_MGMT, + "wpa-psk") + s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_AUTH_ALG, + "open") + s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_PSK, password) + elif "WEP" in ap_sec: + s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_KEY_MGMT, + "None") + s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, + NM.WepKeyType.PASSPHRASE) + s_wifi_sec.set_wep_key(0, password) + profile.add_setting(s_wifi_sec) + + return profile + + +def verify_conn(client, result, data): + """Callback function for add_and_activate_connection_async + + Check if connection completes successfully. Delete the connection if there + is an error. + + """ + try: + act_conn = client.add_and_activate_connection_finish(result) + conn = act_conn.get_connection() + if not all([conn.verify(), + conn.verify_secrets(), + data.verify(), + data.verify_secrets()]): + raise GLib.Error + notify("Added {}".format(conn.get_id())) + except GLib.Error: # pylint: disable=catching-non-exception + try: + notify("Connection to {} failed".format(conn.get_id()), + urgency="critical") + conn.delete_async(None, None, None) + except UnboundLocalError: + pass + finally: + LOOP.quit() + + +def create_ap_list(adapter, active_connections): + """Generate list of access points. Remove duplicate APs , keeping strongest + ones and the active AP + + Args: adapter + active_connections - list of all active connections + Returns: aps - list of access points + active_ap - active AP + active_ap_con - active Connection + adapter + + """ + aps = [] + ap_names = [] + active_ap = adapter.get_active_access_point() + aps_all = sorted(adapter.get_access_points(), + key=lambda a: a.get_strength(), reverse=True) + conns_cur = [i for i in CONNS if + i.get_setting_wireless() is not None and + i.get_setting_wireless().get_mac_address() == + adapter.get_permanent_hw_address()] + try: + ap_conns = active_ap.filter_connections(conns_cur) + active_ap_name = ssid_to_utf8(active_ap) + active_ap_con = [active_conn for active_conn in active_connections + if active_conn.get_connection() in ap_conns] + except AttributeError: + active_ap_name = None + active_ap_con = [] + if len(active_ap_con) > 1: + raise ValueError("Multiple connection profiles match" + " the wireless AP") + active_ap_con = active_ap_con[0] if active_ap_con else None + for nm_ap in aps_all: + ap_name = ssid_to_utf8(nm_ap) + if nm_ap != active_ap and ap_name == active_ap_name: + # Skip adding AP if it's not active but same name as active AP + continue + if ap_name not in ap_names: + ap_names.append(ap_name) + aps.append(nm_ap) + return aps, active_ap, active_ap_con, adapter + + +def notify(message, details=None, urgency="low"): + """Use notify-send if available for notifications + + """ + args = ["-u", urgency, message] + if details is not None: + args.append(details) + + try: + Popen(["notify-send"] + args, + stdout=PIPE, stderr=PIPE).communicate() + except FileNotFoundError: + pass + + +def run(): + """Main script entrypoint""" + active = CLIENT.get_active_connections() + adapter = choose_adapter(CLIENT) + if adapter: + ap_actions = create_ap_actions(*create_ap_list(adapter, active)) + else: + ap_actions = [] + + vpns = [i for i in CONNS if i.is_type(NM.SETTING_VPN_SETTING_NAME)] + try: + wgs = [i for i in CONNS if i.is_type(NM.SETTING_WIREGUARD_SETTING_NAME)] + except AttributeError: + # Workaround for older versions of python-gobject with no wireguard support + wgs = [] + eths = [i for i in CONNS if i.is_type(NM.SETTING_WIRED_SETTING_NAME)] + blues = [i for i in CONNS if i.is_type(NM.SETTING_BLUETOOTH_SETTING_NAME)] + + vpn_actions = create_vpn_actions(vpns, active) + wg_actions = create_wireguard_actions(wgs, active) + eth_actions = create_eth_actions(eths, active) + blue_actions = create_blue_actions(blues, active) + other_actions = create_other_actions(CLIENT) + wwan_installed = is_modemmanager_installed() + if wwan_installed: + gsms = [i for i in CONNS if i.is_type(NM.SETTING_GSM_SETTING_NAME)] + gsm_actions = create_gsm_actions(gsms, active) + wwan_actions = create_wwan_actions(CLIENT) + else: + gsm_actions = [] + wwan_actions = [] + + list_saved = CONF.getboolean('dmenu', 'list_saved', fallback=False) + saved_cons = [i for i in CONNS if i not in vpns + wgs + eths + blues] + if list_saved: + saved_actions = create_saved_actions(saved_cons) + else: + saved_actions = [Action("Saved connections", prompt_saved, [saved_cons])] + + actions = combine_actions(eth_actions, ap_actions, vpn_actions, wg_actions, + gsm_actions, blue_actions, wwan_actions, + other_actions, saved_actions) + sel = get_selection(actions) + sel() + + +if __name__ == '__main__': + run() + +# vim: set et ts=4 sw=4 : diff --git a/scripts/status-bar/arch b/scripts/status-bar/arch index 246f4abd..70f02bdc 100755 --- a/scripts/status-bar/arch +++ b/scripts/status-bar/arch @@ -9,4 +9,4 @@ fi echo $updates > ~/.cache/pacman_updates #echo "$ifg $icon $tfg$(cat ~/.cache/pacman_updates)" -echo "$icon $(cat ~/.cache/pacman_updates)" +echo "^c#a48ead^$icon ^d^ $(cat ~/.cache/pacman_updates)" diff --git a/scripts/status-bar/arch-block b/scripts/status-bar/arch-block deleted file mode 100755 index 6621b6d5..00000000 --- a/scripts/status-bar/arch-block +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -icon=󰮯 -ibg=^b#705B86^ -ifg=^c#fabd2f^ -tfg=^c#292541^ -tbg=^b#cdabb8^ -reset=^d^ - -if ! updates=$(checkupdates 2> /dev/null | wc -l ); then - updates=0t -fi - -echo $updates > ~/.cache/pacman_updates - -echo "$ibg$ifg $icon $tfg$tbg $(cat ~/.cache/pacman_updates) $reset" - diff --git a/scripts/status-bar/battery b/scripts/status-bar/battery index d3660d95..11afcf69 100755 --- a/scripts/status-bar/battery +++ b/scripts/status-bar/battery @@ -15,23 +15,23 @@ ramp90= ramp100= if [[ $bat -lt 10 ]]; then - echo " $ramp10 $bat% " + echo "^c#ebcb8b^$ramp10^d^ $bat% " elif [[ $bat -lt 20 ]]; then - echo " $ramp20 $bat% " + echo "^c#ebcb8b^$ramp20^d^ $bat% " elif [[ $bat -lt "30" ]]; then - echo " $ramp30 $bat% " + echo "^c#ebcb8b^$ramp30^d^ $bat% " elif [[ $bat -lt "40" ]]; then - echo " $ramp40 $bat% " + echo "^c#ebcb8b^$ramp40^d^ $bat% " elif [[ $bat -lt "50" ]]; then - echo " $ramp50 $bat% " + echo "^c#ebcb8b^$ramp50^d^ $bat% " elif [[ $bat -lt "60" ]]; then - echo " $ramp60 $bat% " + echo "^c#ebcb8b^$ramp60^d^ $bat% " elif [[ $bat -lt "70" ]]; then - echo " $ramp70 $bat% " + echo "^c#ebcb8b^$ramp70^d^ $bat% " elif [[ $bat -lt "80" ]]; then - echo " $ramp80 $bat% " + echo "^c#ebcb8b^$ramp80^d^ $bat% " elif [[ $bat -lt "90" ]]; then - echo " $ramp90 $bat% " + echo "^c#ebcb8b^$ramp90^d^ $bat% " elif [[ $bat -le "100" ]]; then - echo " $ramp100 $bat% " + echo "^c#ebcb8b^$ramp100^d^ $bat% " fi diff --git a/scripts/status-bar/battery-blocks b/scripts/status-bar/battery-blocks deleted file mode 100755 index 3ee27fdb..00000000 --- a/scripts/status-bar/battery-blocks +++ /dev/null @@ -1,49 +0,0 @@ -#! /bin/sh - -bat=$(cat /sys/class/power_supply/BAT0/capacity) -status=$(cat /sys/class/power_supply/BAT0/status) - -ramp10=󰁺 -ramp20=󰁻 -ramp30=󰁼 -ramp40=󰁽 -ramp50=󰁾 -ramp60=󰁿 -ramp70=󰂀 -ramp80=󰂁 -ramp90=󰂂 -ramp100=󰁹 - -tbg=^b#cdabb8^ -tfg=^c#292541^ -reset=^d^ - -if [[ $status == "Discharging" ]]; then - ibg=^b#705b86^ -elif [[ $status == "Full" ]]; then - ibg=^b#50FA7B^ -else - ibg=^b#50FA7B^ -fi - -if [[ $bat -lt 10 ]]; then - echo "$ibg$tfg $ramp10 $tbg $bat% $reset" -elif [[ $bat -lt 20 ]]; then - echo "$ibg$tfg $ramp20 $tbg $bat% $reset" -elif [[ $bat -lt "30" ]]; then - echo "$ibg$tfg $ramp30 $tbg $bat% $reset" -elif [[ $bat -lt "40" ]]; then - echo "$ibg$tfg $ramp40 $tbg $bat% $reset" -elif [[ $bat -lt "50" ]]; then - echo "$ibg$tfg $ramp50 $tbg $bat% $reset" -elif [[ $bat -lt "60" ]]; then - echo "$ibg$tfg $ramp60 $tbg $bat% $reset" -elif [[ $bat -lt "70" ]]; then - echo "$ibg$tfg $ramp70 $tbg $bat% $reset" -elif [[ $bat -lt "80" ]]; then - echo "$ibg$tfg $ramp80 $tbg $bat% $reset" -elif [[ $bat -lt "90" ]]; then - echo "$ibg$tfg $ramp90 $tbg $bat% $reset" -elif [[ $bat -le "100" ]]; then - echo "$ibg$tfg $ramp100 $tbg $bat% $reset" -fi diff --git a/scripts/status-bar/capslock b/scripts/status-bar/capslock deleted file mode 100755 index 8658f2ca..00000000 --- a/scripts/status-bar/capslock +++ /dev/null @@ -1,14 +0,0 @@ -#! /bin/sh - -icon=󰘲 -bfg=^b#292541^ -tfg=^c#cc241d^ -reset=^d^ - -cmd=$(cat /sys/class/leds/input3::capslock/brightness) - -if [[ "$cmd" == "1" ]]; then - echo "$tfg$tbg $icon $reset" -else - echo "" -fi diff --git a/scripts/status-bar/clima b/scripts/status-bar/clima deleted file mode 100755 index 0b5f119d..00000000 --- a/scripts/status-bar/clima +++ /dev/null @@ -1,12 +0,0 @@ -#! /bin/sh - -#localización -#initloc=$(curl -s ifconfig.co/city) -#if [ "$initloc" == "La Paz" ]; then -# loc="LAP" -#else -# loc=init-loc -#fi -# obtener clima -#curl -s "wttr.in/$loc?format=%t" -curl -s "wttr.in/?format=%t" diff --git a/scripts/status-bar/clima-icon b/scripts/status-bar/clima-icon deleted file mode 100755 index e1149ba2..00000000 --- a/scripts/status-bar/clima-icon +++ /dev/null @@ -1,27 +0,0 @@ -#! /bin/sh - -estado=$(curl -s "wttr.in/?format=%C" ) -case $estado in - Unknown) icon="";; - Cloudy) icon="";; - Fog) icon="";; - "Heavy rain") icon="";; - "Heavy showers") icon="";; - "Heavy snow") icon="";; - "Heavy snow showers") icon="";; - "Light rain") icon="";; - "Light showers") icon="";; - "Light sleet") icon="";; - "Light sleet showers") icon="";; - "Light snow") icon="";; - "Light snow showers") icon="";; - "Partly cloudy") icon="";; - "Sunny") icon="";; - "Clear") icon="";; - "Thundery heavy rain") icon="";; - "Thundery showers") icon="";; - "Thundery snow showers") icon="";; - "Very cloudy") icon="";; -esac - -echo $icon diff --git a/scripts/status-bar/cpu-temp b/scripts/status-bar/cpu-temp index 01e3d249..7b0878e5 100755 --- a/scripts/status-bar/cpu-temp +++ b/scripts/status-bar/cpu-temp @@ -3,4 +3,4 @@ temp=$(sed 's/[0-9][0-9][0-9]$/°C/' /sys/class/thermal/thermal_zone4/temp) icon= -echo "$icon $temp " +echo "^c#bf616a^$icon^d^ $temp " diff --git a/scripts/status-bar/fecha b/scripts/status-bar/fecha deleted file mode 100755 index 593444ff..00000000 --- a/scripts/status-bar/fecha +++ /dev/null @@ -1,9 +0,0 @@ -#! /bin/sh - -icon= - -cmd=$(date +"%b %e, %R") - - -#echo "$ifg $icon $tfg$cmd" -echo "$icon $cmd" diff --git a/scripts/status-bar/fecha-block b/scripts/status-bar/fecha-block deleted file mode 100755 index 714ac7ca..00000000 --- a/scripts/status-bar/fecha-block +++ /dev/null @@ -1,11 +0,0 @@ -#! /bin/sh - -icon=󰸘 -tfg=^c#292541^ -ibg=^b#705b86^ -tbg=^b#cdabb8^ -reset=^d^ -cmd=$(date +"%b %e, %R") - - -echo "$tfg$ibg$ifg $icon $tbg $cmd $reset" diff --git a/scripts/status-bar/listener b/scripts/status-bar/listener deleted file mode 100755 index 6d1a6d32..00000000 --- a/scripts/status-bar/listener +++ /dev/null @@ -1,10 +0,0 @@ -#! /bin/sh - -while true; do - read -t 1 -n 1 key - - if [[ $key == o ]]; then - notify-send "presionaste la o" - fi -done - diff --git a/scripts/status-bar/network b/scripts/status-bar/network new file mode 100755 index 00000000..9fd90321 --- /dev/null +++ b/scripts/status-bar/network @@ -0,0 +1,19 @@ +#!/bin/sh + +ETH_IT=enp2s0 +WLAN_IT=wlp3s0 + +is_eth_used=$(cat /sys/class/net/${ETH_IT}/carrier) +is_wlan_used=$(cat /sys/class/net/${WLAN_IT}/carrier) + +echo -n "^c#88c0d0^" + +if [ "$is_eth_used" -eq 1 ]; then # wired network is carrying + icon="^d^ " #uF6FF + elif [ "$is_wlan_used" -eq 1 ]; then # wireless network is carrying + icon="直 ^d^ $(nmcli -t -f active,ssid dev wifi | egrep '^yes' | cut -d\' -f2 | cut -d ':' -f2)" #uF1EB + else + icon="^d^" #uf128 # no network +fi + +echo -n $icon diff --git a/scripts/status-bar/red b/scripts/status-bar/red deleted file mode 100755 index 83282b53..00000000 --- a/scripts/status-bar/red +++ /dev/null @@ -1,9 +0,0 @@ -#! /bin/sh - -if [[ $(cat /sys/class/net/wlp*/operstate) == "up" ]]; then - echo " 直 " -else - echo " 睊 " -fi - - diff --git a/scripts/status-bar/red-texto b/scripts/status-bar/red-texto deleted file mode 100755 index 30d499db..00000000 --- a/scripts/status-bar/red-texto +++ /dev/null @@ -1,14 +0,0 @@ -#! /bin/sh - -if [[ $(cat /sys/class/net/wlp*/operstate) == "up" ]]; then - echo " WiFi " -else - ping -c 1 google.com - if [[ $? == 0 ]]; then - echo "Eth" - else - " " - fi -fi - - diff --git a/scripts/status-bar/sep1 b/scripts/status-bar/sep1 deleted file mode 100755 index d44bf717..00000000 --- a/scripts/status-bar/sep1 +++ /dev/null @@ -1,3 +0,0 @@ -#! /bin/sh - -echo "" diff --git a/scripts/status-bar/spotify-bar b/scripts/status-bar/spotify-bar deleted file mode 100755 index 60d1cf17..00000000 --- a/scripts/status-bar/spotify-bar +++ /dev/null @@ -1,14 +0,0 @@ -#! /bin/sh - -icon=" " - -#status=$(~/.local/bin/status-bar/spotify_status.py -f '{artist} - {song}') -status=$(playerctl metadata --format '{{artist}} - {{title}}' | cut -c 1-50) -runstate=$(playerctl status) - -if [[ $runstate == "Playing" ]]; then - echo " $icon $status" -else - echo "" -fi - diff --git a/scripts/status-bar/spotify-block b/scripts/status-bar/spotify-block deleted file mode 100755 index 6fcbe14c..00000000 --- a/scripts/status-bar/spotify-block +++ /dev/null @@ -1,17 +0,0 @@ -#! /bin/sh - -icon="󰓇" -ibg=^b#875B82^ -ifg=^c#1DB954^ -tfg=^c#292541^ -tbg=^b#cdabb8^ -reset=^d^ -status=$(~/.local/bin/status-bar/spotify_status.py) -runstate=$(pgrep -c spotify) - -if [[ $runstate -le 1 ]]; then - echo "" -else - echo "$ibg$ifg $icon $tbg$tfg $status $reset" -fi - diff --git a/scripts/status-bar/spotify_status.py b/scripts/status-bar/spotify_status.py deleted file mode 100755 index eaca49db..00000000 --- a/scripts/status-bar/spotify_status.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/bin/python - -import sys -import dbus -import argparse - - -parser = argparse.ArgumentParser() -parser.add_argument( - '-t', - '--trunclen', - type=int, - metavar='trunclen' -) -parser.add_argument( - '-f', - '--format', - type=str, - metavar='custom format', - dest='custom_format' -) -parser.add_argument( - '-p', - '--playpause', - type=str, - metavar='play-pause indicator', - dest='play_pause' -) -parser.add_argument( - '--font', - type=str, - metavar='the index of the font to use for the main label', - dest='font' -) -parser.add_argument( - '--playpause-font', - type=str, - metavar='the index of the font to use to display the playpause indicator', - dest='play_pause_font' -) - - -args = parser.parse_args() - -def fix_string(string): - # corrects encoding for the python version used - if sys.version_info.major == 3: - return string - else: - return string.encode('utf-8') - -# Default parameters -output = fix_string(u'{play_pause} {artist}: {song}') -trunclen = 35 -play_pause = fix_string(u'\u25B6,\u23F8') # first character is play, second is paused - -label_with_font = '%{{T{font}}}{label}%{{T-}}' -font = args.font -play_pause_font = args.play_pause_font - -# parameters can be overwritten by args -if args.trunclen is not None: - trunclen = args.trunclen -if args.custom_format is not None: - output = args.custom_format -if args.play_pause is not None: - play_pause = args.play_pause - -try: - session_bus = dbus.SessionBus() - spotify_bus = session_bus.get_object( - 'org.mpris.MediaPlayer2.spotify', - '/org/mpris/MediaPlayer2' - ) - - spotify_properties = dbus.Interface( - spotify_bus, - 'org.freedesktop.DBus.Properties' - ) - - metadata = spotify_properties.Get('org.mpris.MediaPlayer2.Player', 'Metadata') - status = spotify_properties.Get('org.mpris.MediaPlayer2.Player', 'PlaybackStatus') - - # Handle play/pause label - - play_pause = play_pause.split(',') - - if status == 'Playing': - play_pause = play_pause[0] - elif status == 'Paused': - play_pause = play_pause[1] - else: - play_pause = str() - - if play_pause_font: - play_pause = label_with_font.format(font=play_pause_font, label=play_pause) - - # Handle main label - - artist = fix_string(metadata['xesam:artist'][0]) if metadata['xesam:artist'] else '' - song = fix_string(metadata['xesam:title']) if metadata['xesam:title'] else '' - - if not artist and not song: - print('') - else: - if len(song) > trunclen: - song = song[0:trunclen] - song += '...' - if ('(' in song) and (')' not in song): - song += ')' - - if font: - artist = label_with_font.format(font=font, label=artist) - song = label_with_font.format(font=font, label=song) - - print(output.format(artist=artist, song=song, play_pause=play_pause)) - -except Exception as e: - if isinstance(e, dbus.exceptions.DBusException): - print('') - else: - print(e) diff --git a/scripts/status-bar/time b/scripts/status-bar/time new file mode 100755 index 00000000..0472711d --- /dev/null +++ b/scripts/status-bar/time @@ -0,0 +1,9 @@ +#! /bin/sh + +icon= + +cmd=$(date +"%R") + + +#echo "$ifg $icon $tfg$cmd" +echo -n "^c#0f111a^^b#bf616a^ $icon $cmd ^d^" diff --git a/scripts/status-bar/volume b/scripts/status-bar/volume deleted file mode 100755 index 707851f9..00000000 --- a/scripts/status-bar/volume +++ /dev/null @@ -1,24 +0,0 @@ -#! /bin/sh - -#mute=$(amixer get Master | awk -F'[][]' 'END{ print $6 }' ) -#vol=$(amixer get Master | awk -F'[][]' 'END{ print $2 }' ) -mute=$(pamixer --get-mute) -vol=$(pamixer --get-volume) -iconmute=婢 -ramp1=奄 -ramp2=奔 -ramp3=墳 - -#if [[ $mute == "true" ]]; then -# echo " $iconmute $vol% " -if [[ $mute == "true" ]]; then - echo " $iconmute mute" -elif [[ "$vol" -ge "100" ]]; then - echo "$ramp3 $vol% " -elif [[ "$vol" -le "33" ]]; then - echo "$ramp1 $vol% " -elif [[ "$vol" -le "66" ]]; then - echo "$ramp2 $vol% " -elif [[ "$vol" -ge "66" ]]; then - echo "$ramp3 $vol% " -fi diff --git a/scripts/status-bar/volume-block b/scripts/status-bar/volume-block deleted file mode 100755 index d33194ef..00000000 --- a/scripts/status-bar/volume-block +++ /dev/null @@ -1,29 +0,0 @@ -#! /bin/sh - -#mute=$(amixer get Master | awk -F'[][]' 'END{ print $6 }' ) -#vol=$(amixer get Master | awk -F'[][]' 'END{ print $2 }' ) -mute=$(pamixer --get-mute) -vol=$(pamixer --get-volume) -iconmute=󰖁 -ramp1=󰕿 -ramp2=󰖀 -ramp3=󰕾 -mbg=^b#cc241d^ -tfg=^c#292541^ -ibg=^b#875b82^ -tbg=^b#cdabb8^ -reset=^d^ - -if [[ $mute == "true" ]]; then - echo "$mbg$tfg $iconmute $tbg$tfg $vol% $reset" -elif [[ "$vol" == "100" ]]; then - echo "$ibg$tfg $ramp3 $tbg$tfg $vol% $reset" -elif [[ "$vol" < "33" ]]; then - echo "$ibg$tfg $ramp1 $tbg$tfg $vol% $reset" -elif [[ "$vol" < "66" ]]; then - echo "$ibg$tfg $ramp2 $tbg$tfg $vol% $reset" -elif [[ "$vol" = "66" ]]; then - echo "$ibg$tfg $ramp2 $tbg$tfg $vol% $reset" -elif [[ "$vol" > "66" ]]; then - echo "$ibg$tfg $ramp3 $tbg$tfg $vol% $reset" -fi diff --git a/scripts/status-bar/weather b/scripts/status-bar/weather new file mode 100755 index 00000000..aa99a77b --- /dev/null +++ b/scripts/status-bar/weather @@ -0,0 +1,31 @@ +#!/bin/sh + +export LOCATION=ankara + +weatherreport="${XDG_DATA_HOME:-$HOME/.local/share}/weatherreport" +getforecast() { curl -sf "wttr.in/$LOCATION" > "$weatherreport" || exit 1 ;} + +# Some very particular and terse stream manipulation. We get the maximum +# precipitation chance and the daily high and low from the downloaded file and +# display them with coresponding emojis. +showweather() { printf "%s" "$(sed '16q;d' "$weatherreport" | + grep -wo "[0-9]*%" | sort -rn | sed "s/^/\^c#81a1c1\^  \^d\^/g;1q" | tr -d '\n')" +sed '13q;d' "$weatherreport" | grep -o "m\\([-+]\\)*[0-9]\\+" | sort -n -t 'm' -k 2n | sed -e 1b -e '$!d' | tr '\n|m' ' ' | awk '{print " ﰕ " $1 "°","^c#ebcb8b^滛 ^d^" $2 "°"}' ;} + +case $BLOCK_BUTTON in + 1) setsid -f "$TERMINAL" -e less -Srf "$weatherreport" ;; + 2) getforecast && showweather ;; + 3) notify-send " Weather module" "\- Left click for full forecast. +- Middle click to update forecast. +: Chance of rain/snow +ﰕ: Daily low +滛: Daily high" ;; + 6) "$TERMINAL" -e "$EDITOR" "$0" ;; +esac + +# The test if our forcecast is updated to the day. If it isn't download a new +# weather report from wttr.in with the above function. +[ "$(stat -c %y "$weatherreport" 2>/dev/null | cut -d' ' -f1)" = "$(date '+%Y-%m-%d')" ] || + getforecast + +showweather diff --git a/scripts/surf_linkselect.sh b/scripts/surf_linkselect.sh new file mode 100755 index 00000000..2fe11384 --- /dev/null +++ b/scripts/surf_linkselect.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env sh +# surf_linkselect.sh: +# Usage: curl somesite.com | surf_linkselect [SURFWINDOWID] [PROMPT] +# Deps: xmllint, dmenu +# Info: +# Designed to be used w/ surf externalpipe patch. Enables keyboard-only +# link selection via dmenu. Given HTML stdin, extracts links one per line +# Selected link is normalized based on current URI and printed to STDOUT. +# Pipe the result to a new surf or xprop _SURF_URI accordingly. +SURF_WINDOW="${1:-$(xprop -root | sed -n '/^_NET_ACTIVE_WINDOW/ s/.* //p')}" +DMENU_PROMPT="${2:-Link}" + +function dump_links_with_titles() { + awk '{ + input = $0; + + $0 = input; + gsub("<[^>]*>", ""); + gsub(/[ ]+/, " "); + gsub("&", "\\&"); + gsub("<", "<"); + gsub(">", ">"); + $1 = $1; + title = ($0 == "" ? "None" : $0); + + $0 = input; + match($0, /\<[ ]*[aA][^>]* [hH][rR][eE][fF]=["]([^"]+)["]/, linkextract); + $0 = linkextract[1]; + gsub(/^[ \t]+/,""); + gsub(/[ \t]+$/,""); + gsub("[ ]", "%20"); + link = $0; + + if (link != "") { + print title ": " link; + } + }' +} + +function link_normalize() { + URI=$1 + awk -v uri=$URI '{ + gsub("&", "\\&"); + + if ($0 ~ /^https?:\/\// || $0 ~ /^\/\/.+$/) { + print $0; + } else if ($0 ~/^#/) { + gsub(/[#?][^#?]+/, "", uri); + print uri $0; + } else if ($0 ~/^\//) { + split(uri, uri_parts, "/"); + print uri_parts[3] $0; + } else { + gsub(/[#][^#]+/, "", uri); + uri_parts_size = split(uri, uri_parts, "/"); + delete uri_parts[uri_parts_size]; + for (v in uri_parts) { + uri_pagestripped = uri_pagestripped uri_parts[v] "/" + } + print uri_pagestripped $0; + } + }' +} + +function link_select() { + tr '\n\r' ' ' | + xmllint --html --xpath "//a" - | + dump_links_with_titles | + awk '!x[$0]++' | + # sort | uniq + dmenu -p "$DMENU_PROMPT" -l 10 -i -w $SURF_WINDOW | + awk -F' ' '{print $NF}' | + link_normalize $(xprop -id $SURF_WINDOW _SURF_URI | cut -d '"' -f 2) +} + +link_select \ No newline at end of file diff --git a/suckless/clipmenu/.travis.yml b/suckless/clipmenu/.travis.yml new file mode 100644 index 00000000..6b3de7ae --- /dev/null +++ b/suckless/clipmenu/.travis.yml @@ -0,0 +1,10 @@ +language: bash + +dist: xenial + +script: + - shellcheck -s bash clipmenu clipmenud clipdel clipfsck clipctl + - tests/test-clipmenu + +matrix: + fast_finish: true diff --git a/suckless/clipmenu/LICENSE b/suckless/clipmenu/LICENSE new file mode 100644 index 00000000..ea9256a3 --- /dev/null +++ b/suckless/clipmenu/LICENSE @@ -0,0 +1,5 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. diff --git a/suckless/clipmenu/Makefile b/suckless/clipmenu/Makefile new file mode 100644 index 00000000..ede39286 --- /dev/null +++ b/suckless/clipmenu/Makefile @@ -0,0 +1,12 @@ +# `dmenu` is not a hard dependency, but you need it unless +# you plan to set CM_LAUNCHER to another value like `rofi` +REQUIRED_BINS := xsel clipnotify +PREFIX ?= /usr +$(foreach bin,$(REQUIRED_BINS),\ + $(if $(shell command -v $(bin) 2> /dev/null),$(info Found `$(bin)`),$(error Missing Dep. Please install `$(bin)`))) + +.PHONY: install + +install: + install --target "${PREFIX}/bin" -D -m755 clipmenu clipmenud clipdel clipctl + install -D -m644 init/clipmenud.service "${PREFIX}/lib/systemd/user/clipmenud.service" diff --git a/suckless/clipmenu/README.md b/suckless/clipmenu/README.md new file mode 100644 index 00000000..de894b01 --- /dev/null +++ b/suckless/clipmenu/README.md @@ -0,0 +1,100 @@ +[![Tests](https://img.shields.io/travis/cdown/clipmenu/develop.svg)](https://travis-ci.org/cdown/clipmenu) + +clipmenu is a simple clipboard manager using [dmenu][] (or [rofi][] with +`CM_LAUNCHER=rofi`) and [xsel][]. + +# Demo + +![Demo](https://cloud.githubusercontent.com/assets/660663/24079784/6f76da94-0c88-11e7-8251-40b1f02ebf3c.gif) + +# Usage + +## clipmenud + +Start `clipmenud`, then run `clipmenu` to select something to put on the +clipboard. For systemd users, a user service called `clipmenud` is packaged as +part of the project. + +For those using a systemd unit and not using a desktop environment which does +it automatically, you must import `$DISPLAY` so that `clipmenud` knows which X +server to use. For example, in your `~/.xinitrc` do this prior to launching +clipmenud: + + systemctl --user import-environment DISPLAY + +## clipmenu + +You may wish to bind a shortcut in your window manager to launch `clipmenu`. + +All args passed to clipmenu are transparently dispatched to dmenu. That is, if +you usually call dmenu with args to set colours and other properties, you can +invoke clipmenu in exactly the same way to get the same effect, like so: + + clipmenu -i -fn Terminus:size=8 -nb '#002b36' -nf '#839496' -sb '#073642' -sf '#93a1a1' + +For a full list of environment variables that clipmenud can take, please see +`clipmenud --help`. + +# Features + +The behavior of `clipmenud` can be customized through environment variables. +Despite being only <300 lines, clipmenu has many useful features, including: + +* Customising the maximum number of clips stored (default 1000) +* Disabling clip collection temporarily with `clipctl disable`, reenabling with + `clipctl enable` +* Not storing clipboard changes from certain applications, like password + managers +* Taking direct ownership of the clipboard +* ...and much more. + +Check `clipmenud --help` to view all possible environment variables and what +they do. If you manage `clipmenud` with `systemd`, you can override the +defaults by using `systemctl --user edit clipmenud` to generate an override +file. + +# Supported launchers + +Any dmenu-compliant application will work, but here are `CM_LAUNCHER` +configurations that are known to work: + +- `dmenu` (the default) +- `fzf` +- `rofi` +- `rofi-script`, for [rofi's script + mode](https://github.com/davatorium/rofi-scripts/tree/master/mode-scripts) + +# Installation + +Several distributions, including Arch and Nix, provide clipmenu as an official +package called `clipmenu`. + +## Manual installation + +If your distribution doesn't provide a package, you can manually install using +`make install` (or better yet, create a package for your distribution!). You +will need `xsel` and `clipnotify` installed, and also `dmenu` unless you plan +to use a different launcher. + +# How does it work? + +clipmenud is less than 300 lines, and clipmenu is less than 100, so hopefully +it should be fairly self-explanatory. However, at the most basic level: + +## clipmenud + +1. `clipmenud` uses [clipnotify](https://github.com/cdown/clipnotify) to wait + for new clipboard events. +2. If `clipmenud` detects changes to the clipboard contents, it writes them out + to the cache directory and an index using a hash as the filename. + +## clipmenu + +1. `clipmenu` reads the index to find all available clips. +2. `dmenu` is executed to allow the user to select a clip. +3. After selection, the clip is put onto the PRIMARY and CLIPBOARD X + selections. + +[dmenu]: http://tools.suckless.org/dmenu/ +[rofi]: https://github.com/DaveDavenport/Rofi +[xsel]: http://www.vergenet.net/~conrad/software/xsel/ diff --git a/suckless/clipmenu/clipctl b/suckless/clipmenu/clipctl new file mode 100755 index 00000000..4249fe29 --- /dev/null +++ b/suckless/clipmenu/clipctl @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +: "${CM_DIR:="${XDG_RUNTIME_DIR-"${TMPDIR-/tmp}"}"}" + +if [[ -z $1 ]] || [[ $1 == --help ]] || [[ $1 == -h ]]; then + cat << 'EOF' +clipctl provides controls for the clipmenud daemon. + +Commands: + enable: enable clip collection + disable: disable clip collection + status: returns "enabled" or "disabled" + toggle: toggles clip collection + version: returns major version + cache-dir: returns the directory used for caching +EOF + exit 0 +fi + +clipmenud_pid=$(pgrep -u "$(id -u)" -nf 'clipmenud$') + +case $1 in + enable|disable|toggle|status) + if [[ -z "$clipmenud_pid" ]]; then + echo "clipmenud is not running" >&2 + exit 2 + fi + ;; +esac + +major_version=6 +cache_dir=$CM_DIR/clipmenu.$major_version.$USER +status_file=$cache_dir/status + +case $1 in + enable) kill -USR2 "$clipmenud_pid" ;; + disable) kill -USR1 "$clipmenud_pid" ;; + status) cat "$status_file" ;; + toggle) + if [[ $(clipctl status) == "enabled" ]]; then + clipctl disable + else + clipctl enable + fi + ;; + version) echo "$major_version" ;; + cache-dir) echo "$cache_dir" ;; + *) + printf 'Unknown command: %s\n' "$1" >&2 + exit 1 + ;; +esac diff --git a/suckless/clipmenu/clipdel b/suckless/clipmenu/clipdel new file mode 100755 index 00000000..12ca1b45 --- /dev/null +++ b/suckless/clipmenu/clipdel @@ -0,0 +1,93 @@ +#!/usr/bin/env bash + +CM_REAL_DELETE=0 +if [[ $1 == -d ]]; then + CM_REAL_DELETE=1 + shift +fi + +shopt -s nullglob + +cache_dir=$(clipctl cache-dir) +cache_file=$cache_dir/line_cache +lock_file=$cache_dir/lock +lock_timeout=2 + +if [[ $1 == --help ]] || [[ $1 == -h ]]; then + cat << 'EOF' +clipdel deletes clipmenu entries matching a regex. By default, just lists what +it would delete, pass -d to do it for real. If no pattern is passed as an argument, +it will try to read one from standard input. + +".*" is special, it will just nuke the entire data directory, including the +line caches and all other state. + +Arguments: + + -d Delete for real. + +Environment variables: + +- $CM_DIR: specify the base directory to store the cache dir in (default: $XDG_RUNTIME_DIR, $TMPDIR, or /tmp) +EOF + exit 0 +fi + +if ! [[ -f $cache_file ]]; then + printf '%s\n' "No line cache file found, no clips exist" >&2 + exit 0 # Well, this is a kind of success... +fi + +if [[ -n $1 ]]; then + raw_pattern=$1 +elif ! [[ -t 0 ]]; then + IFS= read -r raw_pattern +fi + +esc_pattern=${raw_pattern//\#/'\#'} + +# We use 2 separate sed commands so "esc_pattern" matches only the 'clip' text +# without the timestamp (e.g. $> clipdel '^delete_exact_match$') +sed_common_command="s#^[0-9]\+ ##;\\#${esc_pattern}#" + +if ! [[ $raw_pattern ]]; then + printf '%s\n' 'No pattern provided, see --help' >&2 + exit 2 +fi + +exec {lock_fd}> "$lock_file" + +if (( CM_REAL_DELETE )) && [[ "$raw_pattern" == ".*" ]]; then + flock -x -w "$lock_timeout" "$lock_fd" || exit + rm -rf -- "$cache_dir" + mkdir -p -- "$cache_dir" + exit 0 +else + mapfile -t matches < <( + sed -n "${sed_common_command}p" "$cache_file" | + sort -u + ) + + if (( CM_REAL_DELETE )); then + flock -x -w "$lock_timeout" "$lock_fd" || exit + + for match in "${matches[@]}"; do + ck=$(cksum <<< "$match") + rm -f -- "$cache_dir/$ck" + done + + temp=$(mktemp) + # sed 'h' and 'g' here means save and restore the line, so + # timestamps are not removed from non-deleted lines. 'd' deletes the + # line and restarts, skipping 'g'/restore. + # https://www.gnu.org/software/sed/manual/html_node/Other-Commands.html#Other-Commands + sed "h;${sed_common_command}d;g" "$cache_file" > "$temp" + mv -- "$temp" "$cache_file" + + flock -u "$lock_fd" + else + if (( ${#matches[@]} )); then + printf '%s\n' "${matches[@]}" + fi + fi +fi diff --git a/suckless/clipmenu/clipfsck b/suckless/clipmenu/clipfsck new file mode 100755 index 00000000..a9c749df --- /dev/null +++ b/suckless/clipmenu/clipfsck @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +shopt -s nullglob + +cache_dir=$(clipctl cache-dir) +cache_file=$cache_dir/line_cache + +declare -A cksums + +while IFS= read -r line; do + cksum=$(cksum <<< "$line") + cksums["$cksum"]="$line" + + # Are all cache entries represented by a file? + full_file=$cache_dir/$cksum + if ! [[ -f $full_file ]]; then + printf 'cache entry without file: %s -> %s\n' "$line" "$full_file" >&2 + fi +done < <(cut -d' ' -f2- < "$cache_file") + +# Are all files represented by a cache entry? +for file in "$cache_dir"/[012346789]*; do + cksum=${file##*/} + line=${cksums["$cksum"]-_missing_} + if [[ $line == _missing_ ]]; then + printf 'file without cache entry: %s\n' "$file" + fi +done diff --git a/suckless/clipmenu/clipmenu b/suckless/clipmenu/clipmenu new file mode 100755 index 00000000..97b2fe2f --- /dev/null +++ b/suckless/clipmenu/clipmenu @@ -0,0 +1,71 @@ +#!/usr/bin/env bash + +: "${CM_LAUNCHER=dmenu}" +: "${CM_HISTLENGTH=8}" + +shopt -s nullglob + +cache_dir=$(clipctl cache-dir) +cache_file=$cache_dir/line_cache + +# Not -h, see #142 +if [[ $1 == --help ]]; then + cat << 'EOF' +clipmenu is a simple clipboard manager using dmenu and xsel. Launch this +when you want to select a clip. + +All arguments are passed through to dmenu itself. + +Environment variables: + +- $CM_DIR: specify the base directory to store the cache dir in (default: $XDG_RUNTIME_DIR, $TMPDIR, or /tmp) +- $CM_HISTLENGTH: specify the number of lines to show in dmenu/rofi (default: 8) +- $CM_LAUNCHER: specify a dmenu-compatible launcher (default: dmenu) +- $CM_OUTPUT_CLIP: if set, output clip selection to stdout +EOF + exit 0 +fi + +if ! [[ -f "$cache_file" ]]; then + printf '%s\n' 'No cache file yet, did you run clipmenud?' + exit 2 +fi + +# Blacklist of non-dmenu launchers +launcher_args=(-l "${CM_HISTLENGTH}") +if [[ "$CM_LAUNCHER" == fzf ]]; then + launcher_args=() +fi + +# rofi supports dmenu-like arguments through the -dmenu flag +[[ "$CM_LAUNCHER" == rofi ]] && set -- -dmenu "$@" + +list_clips() { + LC_ALL=C sort -rnk 1 < "$cache_file" | cut -d' ' -f2- | awk '!seen[$0]++' +} + +if [[ "$CM_LAUNCHER" == rofi-script ]]; then + if (( $# )); then + chosen_line="${!#}" + else + list_clips + exit + fi +else + chosen_line=$(list_clips | "$CM_LAUNCHER" "${launcher_args[@]}" "$@") + launcher_exit=$? +fi + +[[ $chosen_line ]] || exit 1 +file=$cache_dir/$(cksum <<< "$chosen_line") +[[ -f "$file" ]] || exit 2 + +for selection in clipboard primary; do + xsel --logfile /dev/null -i --"$selection" < "$file" +done + +if (( CM_OUTPUT_CLIP )); then + cat "$file" +fi + +exit "${launcher_exit:-"$?"}" diff --git a/suckless/clipmenu/clipmenud b/suckless/clipmenu/clipmenud new file mode 100755 index 00000000..db69d1ab --- /dev/null +++ b/suckless/clipmenu/clipmenud @@ -0,0 +1,253 @@ +#!/usr/bin/env bash + +: "${CM_ONESHOT=0}" +: "${CM_OWN_CLIPBOARD=0}" +: "${CM_SYNC_PRIMARY_TO_CLIPBOARD=0}" +: "${CM_DEBUG=0}" + +: "${CM_MAX_CLIPS:=1000}" +# Buffer to batch to avoid calling too much. Only used if CM_MAX_CLIPS >0. +CM_MAX_CLIPS_THRESH=$(( CM_MAX_CLIPS + 10 )) + +: "${CM_SELECTIONS:=clipboard primary}" +read -r -a selections <<< "$CM_SELECTIONS" + +cache_dir=$(clipctl cache-dir) +cache_file=$cache_dir/line_cache +status_file=$cache_dir/status + +# lock_file: lock for *one* iteration of clipboard capture/propagation +# session_lock_file: lock to prevent multiple clipmenud daemons +lock_file=$cache_dir/lock +session_lock_file=$cache_dir/session_lock +lock_timeout=2 +has_xdotool=0 + +_xsel() { timeout 1 xsel --logfile /dev/null "$@"; } + +error() { printf 'ERROR: %s\n' "${1?}" >&2; } +info() { printf 'INFO: %s\n' "${1?}"; } +die() { + error "${2?}" + exit "${1?}" +} + +make_line_cksums() { while read -r line; do cksum <<< "${line#* }"; done; } + +get_first_line() { + data=${1?} + + # We look for the first line matching regex /./ here because we want the + # first line that can provide reasonable context to the user. + awk -v limit=300 ' + BEGIN { printed = 0; } + printed == 0 && NF { + $0 = substr($0, 0, limit); + printf("%s", $0); + printed = 1; + } + END { + if (NR > 1) + printf(" (%d lines)", NR); + printf("\n"); + }' <<< "$data" +} + +debug() { (( CM_DEBUG )) && printf '%s\n' "$@" >&2; } + +sig_disable() { + info "Received disable signal, suspending clipboard capture" + _CM_DISABLED=1 + _CM_FIRST_DISABLE=1 + echo "disabled" > "$status_file" + [[ -v _CM_CLIPNOTIFY_PID ]] && kill "$_CM_CLIPNOTIFY_PID" +} + +sig_enable() { + if ! (( _CM_DISABLED )); then + info "Received enable signal but we're not disabled, so doing nothing" + return + fi + + # Still store the last data so we don't end up eventually putting it in the + # clipboard if it wasn't changed + for selection in "${selections[@]}"; do + data=$(_xsel -o --"$selection"; printf x) + last_data_sel[$selection]=${data%x} + done + + info "Received enable signal, resuming clipboard capture" + _CM_DISABLED=0 + echo "enabled" > "$status_file" +} + +kill_background_jobs() { + # While we usually _are_, there are no guarantees that we're the process + # group leader. As such, all we can do is look at the pending jobs. Bash + # avoids a subshell here, so the job list is in the right shell. + local bg + bg=$(jobs -p) + + # Don't log `kill' failures, since with KillMode=control-group, we're + # racing with init. + [[ $bg ]] && kill -- "$bg" 2>/dev/null +} + +if [[ $1 == --help ]] || [[ $1 == -h ]]; then + cat << 'EOF' +clipmenud collects and caches what's on the clipboard. You can manage its +operation with clipctl. + +Environment variables: + +- $CM_DEBUG: turn on debugging output (default: 0) +- $CM_DIR: specify the base directory to store the cache dir in (default: $XDG_RUNTIME_DIR, $TMPDIR, or /tmp) +- $CM_MAX_CLIPS: soft maximum number of clips to store, 0 for inf. At $CM_MAX_CLIPS + 10, the number of clips is reduced to $CM_MAX_CLIPS (default: 1000) +- $CM_ONESHOT: run once immediately, do not loop (default: 0) +- $CM_OWN_CLIPBOARD: take ownership of the clipboard. Note: this may cause missed copies if some other application also handles the clipboard directly (default: 0) +- $CM_SELECTIONS: space separated list of the selections to manage (default: "clipboard primary") +- $CM_SYNC_PRIMARY_TO_CLIPBOARD: sync selections from primary to clipboard immediately (default: 0) +- $CM_IGNORE_WINDOW: disable recording the clipboard in windows where the windowname matches the given regex (e.g. a password manager), do not ignore any windows if unset or empty (default: unset) +EOF + exit 0 +fi + +[[ $DISPLAY ]] || die 2 'The X display is unset, is your X server running?' + +# It's ok that this only applies to the final directory. +# shellcheck disable=SC2174 +mkdir -p -m0700 "$cache_dir" +echo "enabled" > "$status_file" + +exec {session_lock_fd}> "$session_lock_file" +flock -x -n "$session_lock_fd" || + die 2 "Can't lock session file -- is another clipmenud running?" + +declare -A last_data_sel +declare -A updated_sel + +command -v clipnotify >/dev/null 2>&1 || die 2 "clipnotify not in PATH" +command -v xdotool >/dev/null 2>&1 && has_xdotool=1 + +if [[ $CM_IGNORE_WINDOW ]] && ! (( has_xdotool )); then + echo "WARN: CM_IGNORE_WINDOW does not work without xdotool, which is not installed" >&2 +fi + +exec {lock_fd}> "$lock_file" + +trap sig_disable USR1 +trap sig_enable USR2 +trap 'trap - INT TERM EXIT; kill_background_jobs; exit 0' INT TERM EXIT + +while true; do + if ! (( CM_ONESHOT )); then + # Make sure we're interruptible for the sig_{en,dis}able traps + clipnotify & + _CM_CLIPNOTIFY_PID="$!" + wait "$_CM_CLIPNOTIFY_PID" + fi + + if (( _CM_DISABLED )); then + # The first one will just be from interrupting `wait`, so don't print + if (( _CM_FIRST_DISABLE )); then + unset _CM_FIRST_DISABLE + else + info "Got a clipboard notification, but we are disabled, skipping" + fi + continue + fi + + if [[ $CM_IGNORE_WINDOW ]] && (( has_xdotool )); then + windowname="$(xdotool getactivewindow getwindowname)" + if [[ "$windowname" =~ $CM_IGNORE_WINDOW ]]; then + debug "ignoring clipboard because windowname \"$windowname\" matches \"${CM_IGNORE_WINDOW}\"" + continue + fi + fi + + if ! flock -x -w "$lock_timeout" "$lock_fd"; then + if (( CM_ONESHOT )); then + die 1 "Timed out waiting for lock" + else + error "Timed out waiting for lock, skipping this iteration" + continue + fi + fi + + for selection in "${selections[@]}"; do + updated_sel[$selection]=0 + + data=$(_xsel -o --"$selection"; printf x) + data=${data%x} # avoid trailing newlines being stripped + + [[ $data == *[^[:space:]]* ]] || continue + [[ $last_data == "$data" ]] && continue + [[ ${last_data_sel[$selection]} == "$data" ]] && continue + + if [[ $last_data && $data == "$last_data"* ]] || + [[ $last_data && $data == *"$last_data" ]]; then + # Don't actually remove the file yet, because it might be + # referenced by an older entry. These will be dealt with at vacuum. + debug "$selection: $last_data is a possible partial of $data" + previous_size=$(wc -c <<< "$last_cache_file_output") + truncate -s -"$previous_size" "$cache_file" + fi + + first_line=$(get_first_line "$data") + debug "New clipboard entry on $selection selection: \"$first_line\"" + + cache_file_output="$(date +%s%N) $first_line" + filename="$cache_dir/$(cksum <<< "$first_line")" + last_cache_file_output=$cache_file_output + last_data=$data + last_data_sel[$selection]=$data + updated_sel[$selection]=1 + + debug "Writing $data to $filename" + printf '%s' "$data" > "$filename" + debug "Writing $cache_file_output to $cache_file" + printf '%s\n' "$cache_file_output" >> "$cache_file" + + if (( CM_OWN_CLIPBOARD )) && [[ $selection == clipboard ]]; then + # Only clipboard, since apps like urxvt will unhilight for PRIMARY + _xsel -o --clipboard | _xsel -i --clipboard + fi + done + + if (( CM_SYNC_PRIMARY_TO_CLIPBOARD )) && (( updated_sel[primary] )); then + _xsel -o --primary | _xsel -i --clipboard + fi + + # The cache file may not exist if this is the first run and data is skipped + if (( CM_MAX_CLIPS )) && [[ -f "$cache_file" ]] && (( "$(wc -l < "$cache_file")" > CM_MAX_CLIPS_THRESH )); then + info "Trimming clip cache to CM_MAX_CLIPS ($CM_MAX_CLIPS)" + trunc_tmp=$(mktemp) + tail -n "$CM_MAX_CLIPS" "$cache_file" | uniq > "$trunc_tmp" + mv -- "$trunc_tmp" "$cache_file" + + # Vacuum up unreferenced clips. They may either have been + # unreferenced by the above CM_MAX_CLIPS code, or they may be old + # possible partials. + declare -A cksums + while IFS= read -r line; do + cksum=$(cksum <<< "$line") + cksums["$cksum"]="$line" + done < <(cut -d' ' -f2- < "$cache_file") + + num_vacuumed=0 + for file in "$cache_dir"/[012346789]*; do + cksum=${file##*/} + if [[ ${cksums["$cksum"]-_missing_} == _missing_ ]]; then + debug "Vacuuming due to lack of reference: $file" + (( ++num_vacuumed )) + rm -- "$file" + fi + done + unset cksums + info "Vacuumed $num_vacuumed clip files." + fi + + flock -u "$lock_fd" + + (( CM_ONESHOT )) && break +done diff --git a/suckless/clipmenu/init/clipmenud.service b/suckless/clipmenu/init/clipmenud.service new file mode 100644 index 00000000..c36ab4ae --- /dev/null +++ b/suckless/clipmenu/init/clipmenud.service @@ -0,0 +1,21 @@ +[Unit] +Description=Clipmenu daemon + +[Service] +ExecStart=/usr/bin/clipmenud +Restart=always +RestartSec=500ms + +MemoryDenyWriteExecute=yes +NoNewPrivileges=yes +ProtectControlGroups=yes +ProtectKernelTunables=yes +RestrictAddressFamilies= +RestrictRealtime=yes + +# We don't need to do any clean up, so if something hangs (borked xclip, etc), +# it's going to stay that way. Just forcefully kill and get it over with. +TimeoutStopSec=2 + +[Install] +WantedBy=default.target diff --git a/suckless/clipmenu/tests/test-clipmenu b/suckless/clipmenu/tests/test-clipmenu new file mode 100755 index 00000000..8fe9561f --- /dev/null +++ b/suckless/clipmenu/tests/test-clipmenu @@ -0,0 +1,93 @@ +#!/usr/bin/env bash + +set -x +set -e +set -o pipefail + +dir=$(./clipctl cache-dir) +cache_file=$dir/line_cache + +if [[ $0 == /* ]]; then + location=${0%/*} +else + location=$PWD/${0#./} + location=${location%/*} +fi + +cat - "$location/../clipmenu" > /tmp/clipmenu << 'EOF' +#!/usr/bin/env bash + +shopt -s expand_aliases + +shim() { + printf '%s args:' "$1" >&2 + printf ' %q' "${@:2}" >&2 + printf '\n' >&2 + + i=0 + + while IFS= read -r line; do + let i++ + printf '%s line %d stdin: %s\n' "$1" "$i" "$line" >&2 + done + + if [[ -v SHIM_STDOUT ]]; then + printf '%s\n' "$SHIM_STDOUT" + fi +} + +# Cannot be an alias due to expansion order with $CM_LAUNCHER +dmenu() { + SHIM_STDOUT="Selected text. (2 lines)" shim dmenu "$@" +} + +rofi() { + SHIM_STDOUT="Selected text. (2 lines)" shim rofi "$@" +} + +alias xsel='shim xsel' +alias xclip='shim xclip' +alias clipctl='./clipctl' +EOF + +chmod a+x /tmp/clipmenu + +rm -rf "$dir" +mkdir -p "$dir" + +cat > "$cache_file" << 'EOF' +1234 Selected text. (2 lines) +1235 Selected text 2. (2 lines) +EOF + +cat > "$dir/$(cksum <<< 'Selected text. (2 lines)')" << 'EOF' +Selected text. +Yes, it's selected text. +EOF + +### TESTS ### + +temp=$(mktemp) + +trap 'cat "$temp"' EXIT + +/tmp/clipmenu --foo bar > "$temp" 2>&1 + +# Arguments are transparently passed to dmenu +grep -Fxq 'dmenu args: -l 8 --foo bar' "$temp" + +# Output from cache file should get to dmenu, reversed +grep -Fxq 'dmenu line 1 stdin: Selected text 2. (2 lines)' "$temp" +grep -Fxq 'dmenu line 2 stdin: Selected text. (2 lines)' "$temp" + +# xsel should copy both to clipboard *and* primary +grep -Fxq 'xsel args: --logfile /dev/null -i --clipboard' "$temp" +grep -Fxq 'xsel args: --logfile /dev/null -i --primary' "$temp" + +grep -Fxq 'xsel line 1 stdin: Selected text.' "$temp" +grep -Fxq "xsel line 2 stdin: Yes, it's selected text." "$temp" + +CM_LAUNCHER=rofi /tmp/clipmenu --foo bar > "$temp" 2>&1 + +# We have a special case to add -dmenu for rofi +grep -Fxq 'rofi args: -l 8 -dmenu --foo bar' "$temp" diff --git a/suckless/clipmenu/tests/test-perf b/suckless/clipmenu/tests/test-perf new file mode 100755 index 00000000..62998a8e --- /dev/null +++ b/suckless/clipmenu/tests/test-perf @@ -0,0 +1,87 @@ +#!/usr/bin/env bash + +msg() { + printf '>>> %s\n' "$@" >&2 +} + +dir=$(clipctl cache-dir) +cache_file=$dir/line_cache + +log=$(mktemp) +tim=$(mktemp) +clipmenu_shim=$(mktemp) +num_files=1500 + +trap 'rm -f -- "$log" "$tim" "$clipmenu_shim"' EXIT + +if [[ $0 == /* ]]; then + location=${0%/*} +else + location=$PWD/${0#./} + location=${location%/*} +fi + +msg 'Setting up edited clipmenu' + +cat - "$location/../clipmenu" > /tmp/clipmenu << EOF +#!/usr/bin/env bash + +exec 3>&2 2> >(tee "$log" | + sed -u 's/^.*$/now/' | + date -f - +%s.%N > "$tim") +set -x + +dmenu() { :; } +xsel() { :; } + +EOF + +chmod a+x /tmp/clipmenu + +if ! (( NO_RECREATE )); then + rm -rf "$dir" + mkdir -p "$dir" + + msg "Writing $num_files clipboard files" + + for (( i = 0; i <= num_files; i++ )); do + (( i % 100 )) || printf '%s... ' "$i" + + line_len=$(( (RANDOM % 10000) + 1 )) + num_lines=$(( (RANDOM % 10) + 1 )) + data=$( + tr -dc 'a-zA-Z0-9' < /dev/urandom | + fold -w "$line_len" | + head -"$num_lines" + ) + read -r first_line_raw <<< "$data" + printf -v first_line '%s (%s lines)\n' "$first_line_raw" "$num_lines" + printf '%d %s' "$i" "$first_line" >> "$cache_file" + fn=$dir/$(cksum <<< "$first_line") + printf '%s' "$data" > "$fn" + done + + printf 'done\n' +else + msg 'Not nuking/creating new clipmenu files' +fi + +msg 'Running modified clipmenu' + +time /tmp/clipmenu + +(( TIME_ONLY )) && exit 0 + +msg 'Displaying perf data' + +# modified from http://stackoverflow.com/a/20855353/945780 +paste <( + while read -r tim ;do + [ -z "$last" ] && last=${tim//.} && first=${tim//.} + crt=000000000$((${tim//.}-10#0$last)) + ctot=000000000$((${tim//.}-10#0$first)) + printf "%12.9f %12.9f\n" ${crt:0:${#crt}-9}.${crt:${#crt}-9} \ + ${ctot:0:${#ctot}-9}.${ctot:${#ctot}-9} + last=${tim//.} + done < "$tim" +) "$log" | less diff --git a/suckless/dwm/, b/suckless/dwm/, deleted file mode 100644 index ce35be64..00000000 --- a/suckless/dwm/, +++ /dev/null @@ -1,245 +0,0 @@ -/* See LICENSE file for copyright and license details. */ - -#include -/* appearance */ -static const unsigned int borderpx = 3; /* border pixel of windows */ -static const unsigned int gappx = 6; -static const unsigned int snap = 32; /* snap pixel */ -static const int rmaster = 0; /* 1 = master at right*/ -static const int showbar = 1; /* 0 means no bar */ -static const int topbar = 1; /* 0 means bottom bar */ -static const int user_bh = 27; /* 0 means that dwm will calculate bar height, >= 1 means dwm will user_bh as bar height */ -static const int tag_padding = 0; -static const int vertpad = 0; /* vertical padding of bar */ -static const int sidepad = 0; /* horizontal padding of bar */ -static const char *fonts[] = {"Hack Nerd Font:Regular:size=10", "Material Design Icons:Regular:pixelsize=16:antialias=true"}; -static const char dmenufont[] = "Hack Nerd Font:size=10"; -static const char fore[] = "#f8f8f2"; -static const char back[] = "#282a36"; -static const char border[] = "#f8f8f2"; -static const char col0[] = "#000000"; -static const char col1[] = "#FF5555"; -static const char col2[] = "#50FA7B"; -static const char col3[] = "#F1FA8C"; -static const char col4[] = "#BD93F9"; -static const char col5[] = "#FF79C6"; -static const char col6[] = "#8BE9FD"; -static const char col7[] = "#BFBFBF"; -static const char col8[] = "#4D4D4D"; -static const char col9[] = "#FF6E67"; -static const char col10[] = "#5AF78E"; -static const char col11[] = "#F4F99D"; -static const char col12[] = "#CAA9FA"; -static const char col13[] = "#FF92D0"; -static const char col14[] = "#9AEDFE"; -static const char col15[] = "#E6E6E6"; - -static const char spotify[]= "#1FC167"; - - -static const char *colors[][3] = { - /* fg bg border */ - [SchemeNorm] = { fore, back, back }, // \x0b - [SchemeSel] = { fore, back, border }, // \x0c - [SchemeStatus] = { fore, back, border }, // \x0d Statusbar right - [SchemeTagsSel] = { col4, back, border }, // \x0e Tagbar left selected - [SchemeTagsNorm] = { fore, back, border }, // \x0f Tagbar left unselected - [SchemeInfoSel] = { fore, back, border }, // \x10 infobar middle selected - [SchemeInfoNorm] = { fore, back, border }, // \x11 infobar middle unselected - [SchemeCol1] = { col1, back, col0 }, // \x12 - [SchemeCol2] = { col2, back, col0 }, // \x13 - [SchemeCol3] = { col3, back, col0 }, // \x14 - [SchemeCol4] = { col4, back, col0 }, // \x15 - [SchemeCol5] = { col5, back, col0 }, // \x16 - [SchemeCol6] = { col6, back, col0 }, // \x17 - [SchemeCol7] = { col7, back, col0 }, // \x18 - [SchemeCol8] = { col8, back, col0 }, // \x19 - [SchemeCol9] = { col9, back, col0 }, // \x1a - [SchemeCol10] = { col10, back, col0 }, // \x1b - [SchemeCol11] = { col11, back, col0 }, // \x1c - [SchemeCol12] = { spotify, back, col0 }, // \x1d Spotify -}; - -/* tagging */ -static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"}; -//static const char *alttags[] = { "󰄯", "󰄯", "󰄯", "󰄯"}; - -static const Rule rules[] = { - /* xprop(1): - * WM_CLASS(STRING) = instance, class - * WM_NAME(STRING) = title - */ - /* class instance title tags mask isfloating monitor */ - { "discord", NULL, NULL, 1 << 8, 0, -1 }, - { "Termite", NULL, NULL, 1 << 0, 0, -1 }, - { "firefoxdeveloperedition", NULL, NULL, 1 << 1, 0, -1 }, - { "Tor Browser", NULL, NULL, 1 << 1, 0, -1 }, - { "Chromium", NULL, NULL, 1 << 1, 0, -1 }, - { "zoom", NULL, NULL, 1 << 4, 0, -1 }, - { "TelegramDesktop", NULL, NULL, 1 << 8, 0, -1 }, - { "whatsapp-nativefier-d52542", NULL, NULL, 1 << 8, 0, -1 }, - { "neomutt", NULL, NULL, 1 << 7, 0, -1 }, - { "Sublime_Text", NULL, NULL, 1 << 2, 0, -1 }, - { "code-oss", NULL, NULL, 1 << 2, 0, -1 }, - { "jetbrains-idea", NULL, NULL, 1 << 2, 0, -1 }, - { "Nemo", NULL, NULL, 1 << 3, 1, -1 }, - { "Spotify", NULL, NULL, 1 << 9, 0, -1 }, -}; - -/* layout(s) */ -static const float mfact = 0.5; /* factor of master area size [0.05..0.95] */ -static const int nmaster = 1; /* number of clients in master area */ -static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */ - -#include "fibonacci.c" -#include "layouts.c" -static const Layout layouts[] = { - /* symbol arrange function */ - { "鉶", tile }, /* first entry is default */ - { "", dwindle }, - { "ﱖ", grid }, - { "", centeredmaster }, - { "", centeredfloatingmaster }, - { "[M]", monocle }, - { "[D]", deck }, - { NULL, NULL }, -}; - -/* key definitions */ -#define MODKEY Mod4Mask -#define TAGKEYS(KEY,TAG) \ - { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ - { MODKEY|Mod1Mask, KEY, toggleview, {.ui = 1 << TAG} }, \ - { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ - { MODKEY|ControlMask, KEY, toggletag, {.ui = 1 << TAG} }, - -/* COSAS QUE TENGO QUE AVERIGUAR COMO QUITAR */ - -/* helper for spawning shell commands in the pre dwm-5.0 fashion */ -#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } -static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ -static const char *dmenucmd[] = { "/usr/bin/rofi","-show","drun", NULL }; -static const char *termcmd[] = { "/usr/bin/termite", "--title", "Terminal", NULL }; -static const char *upvol[] = { "/usr/bin/pactl", "set-sink-volume", "0", "+5%", NULL }; -static const char *downvol[] = { "/usr/bin/pactl", "set-sink-volume", "0", "-5%", NULL }; -static const char *mutevol[] = { "/usr/bin/pactl", "set-sink-mute", "0", "toggle", NULL }; - -static const char *upbright[] = {"/usr/bin/xbacklight","-inc","10",NULL}; -static const char *downbright[] = {"/usr/bin/xbacklight","-dec","10",NULL}; - -static const char *lock[] = {"/usr/bin/betterlockscreen","-l","-t","Stay the fuck out!",NULL}; -static const char *clipmenu[] = {"/usr/bin/clipmenu","-i",NULL}; -static const char *play[] = {"/usr/bin/playerctl","play-pause",NULL}; -static const char *prev[] = {"/usr/bin/playerctl","previous",NULL}; -static const char *next[] = {"/usr/bin/playerctl","next",NULL}; -static const char *outmenu[] = {"/home/yigit/.scripts/dmenu-logout"}; -static const char *bwmenu[] = {"/usr/bin/bwmenu", "--auto-lock", "-1"}; - -static const char *trackpad[] = {"/home/yigit/.scripts/toggle_touchpad.sh"}; - -static const char *screenshot[] = { "scrot","-d","3", "%Y-%m-%d-%s_$wx$h.jpg", "-e","xclip -selection clipboard -t image/jpg < $f; mv $f ~/Pictures/Screenshots/;dunstify -a 'SNAP' 'Email taken'", NULL }; -static const char *windowshot[] = { "scrot", "-u", "-d","3", "%Y-%m-%d-%s_$wx$h.jpg", "-e","xclip -selection clipboard -t image/jpg < $f; mv $f ~/Pictures/Screenshots/;dunstify -a 'SNAP' 'Email taken'", NULL }; - -/* commands */ -#include "movestack.c" -#include "shiftview.c" -static Key keys[] = { - /* modifier key function argument */ - { MODKEY, XK_d, spawn, {.v = dmenucmd } }, - { MODKEY, XK_p, spawn, {.v = bwmenu } }, - { MODKEY, 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_s, incnmaster, {.i = -1 } }, - { MODKEY, XK_h, setmfact, {.f = -0.05} }, - { MODKEY, XK_l, setmfact, {.f = +0.05} }, - { MODKEY|ShiftMask, XK_Return, zoom, {0} }, - { MODKEY, XK_Tab, view, {0} }, - { MODKEY, XK_q, killclient, {0} }, - { MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } }, /*Mover ventana hacia abajo*/ - { MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } }, /*Mover ventana hacia arriba*/ - { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, /*tiled*/ - { MODKEY|Mod1Mask, XK_f, setlayout, {.v = &layouts[1]} }, /*Spiral*/ - { MODKEY|Mod1Mask, XK_g, setlayout, {.v = &layouts[2]} }, /*Grid*/ - { MODKEY|Mod1Mask, XK_c, setlayout, {.v = &layouts[3]} }, /*center*/ - { MODKEY, XK_m, setlayout, {.v = &layouts[5]} }, /*monocle*/ - { MODKEY|ShiftMask, XK_m, setlayout, {.v = &layouts[6]} }, /*Deck*/ - { MODKEY, XK_s, togglefloating, {0} }, /*float*/ - { MODKEY, XK_f, togglefullscr, {0} }, /*Fullscreen*/ - { MODKEY|Mod1Mask, XK_comma, cyclelayout, {.i = -1 } }, /*Ciclar layouts*/ - { MODKEY|Mod1Mask, XK_period, cyclelayout, {.i = +1 } }, /*Ciclar layouts*/ - { MODKEY, XK_a, view, {.ui = ~0 } }, - { MODKEY|ShiftMask, XK_a, 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 } }, - /*Monitores*/ - { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, /*Mandar ventana a monitor anterior*/ - { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, /*Mandar ventana a monitor siguiente*/ - 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) - TAGKEYS( XK_0, 9) - { MODKEY|ShiftMask, XK_q, spawn, {.v = outmenu} }, - { MODKEY|ShiftMask, XK_t, spawn, {.v = trackpad} }, - { MODKEY, XK_x, spawn, {.v = lock } }, - { MODKEY, XK_c, spawn, {.v = clipmenu } }, - { 0, XF86XK_AudioLowerVolume, spawn, {.v = downvol } }, - { 0, XF86XK_MonBrightnessUp, spawn, {.v = upbright } }, - { 0, XF86XK_MonBrightnessDown, spawn, {.v = downbright } }, - { 0, XF86XK_AudioMute, spawn, {.v = mutevol } }, - { 0, XF86XK_AudioRaiseVolume, spawn, {.v = upvol } }, - { 0, XF86XK_AudioPrev, spawn, {.v = prev } }, - { 0, XF86XK_AudioPlay, spawn, {.v = play } }, - { 0, XF86XK_AudioNext, spawn, {.v = next } }, - { 0, XK_Print, spawn, {.v = screenshot } }, - { MODKEY, XK_Print, spawn, {.v = windowshot } }, - -}; - -/* button definitions */ -/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ - -static Button buttons[] = { - /* click event mask button function argument */ - { ClkLtSymbol, 0, Button1, setlayout, {0} }, - { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, - { 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} }, -}; - -/* -static Button buttons[] = { - // click event mask button function argument - { ClkLtSymbol, 0, Button1, cyclelayout, {.i = +1 } }, - { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[5]} }, - { ClkWinTitle, 0, Button2, zoom, {0} }, - { ClkStatusText, 0, Button1, sigdwmblocks, {.i = 1} }, - { ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2} }, - { ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3} }, - { 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} }, - { ClkClientWin, 0, Button1, winview, {0} }, -}; -*/ diff --git a/suckless/dwm/.gitignore b/suckless/dwm/.gitignore new file mode 100644 index 00000000..ca093f81 --- /dev/null +++ b/suckless/dwm/.gitignore @@ -0,0 +1,5 @@ +*.o +dwm +dwm-msg +config.h +patches.h diff --git a/suckless/dwm/Makefile b/suckless/dwm/Makefile index 77bcbc02..c2ea8dfd 100644 --- a/suckless/dwm/Makefile +++ b/suckless/dwm/Makefile @@ -6,7 +6,13 @@ include config.mk SRC = drw.c dwm.c util.c OBJ = ${SRC:.c=.o} +# FreeBSD users, prefix all ifdef, else and endif statements with a . for this to work (e.g. .ifdef) + +ifdef YAJLLIBS +all: options dwm dwm-msg +else all: options dwm +endif options: @echo dwm build options: @@ -17,16 +23,25 @@ options: .c.o: ${CC} -c ${CFLAGS} $< -${OBJ}: config.h config.mk +${OBJ}: config.h config.mk patches.h config.h: cp config.def.h $@ +patches.h: + cp patches.def.h $@ + dwm: ${OBJ} ${CC} -o $@ ${OBJ} ${LDFLAGS} +ifdef YAJLLIBS +dwm-msg: + ${CC} -o $@ patch/ipc/dwm-msg.c ${LDFLAGS} +endif + clean: rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz + rm -f dwm-msg dist: clean mkdir -p dwm-${VERSION} @@ -39,7 +54,14 @@ dist: clean install: all mkdir -p ${DESTDIR}${PREFIX}/bin cp -f dwm ${DESTDIR}${PREFIX}/bin +ifdef YAJLLIBS + cp -f dwm-msg ${DESTDIR}${PREFIX}/bin +endif + #cp -f patch/dwmc ${DESTDIR}${PREFIX}/bin chmod 755 ${DESTDIR}${PREFIX}/bin/dwm +ifdef YAJLLIBS + chmod 755 ${DESTDIR}${PREFIX}/bin/dwm-msg +endif mkdir -p ${DESTDIR}${MANPREFIX}/man1 sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1 chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1 diff --git a/suckless/dwm/Makefile.bak b/suckless/dwm/Makefile.bak deleted file mode 100644 index da3269d7..00000000 --- a/suckless/dwm/Makefile.bak +++ /dev/null @@ -1,50 +0,0 @@ -# dwm - dynamic window manager -# See LICENSE file for copyright and license details. - -include config.mk - -SRC = drw.c dwm.c util.c -OBJ = ${SRC:.c=.o} - -all: options dwm - -options: - @echo dwm build options: - @echo "CFLAGS = ${CFLAGS}" - @echo "LDFLAGS = ${LDFLAGS}" - @echo "CC = ${CC}" - -.c.o: - ${CC} -c ${CFLAGS} $< - -${OBJ}: config.h config.mk - -config.h: - cp config.def.h $@ - -dwm: ${OBJ} - ${CC} -o $@ ${OBJ} ${LDFLAGS} - -clean: - rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz - -dist: clean - mkdir -p dwm-${VERSION} - cp -R LICENSE Makefile README config.def.h config.mk\ - dwm.1 drw.h util.h ${SRC} dwm.png transient.c dwm-${VERSION} - tar -cf dwm-${VERSION}.tar dwm-${VERSION} - gzip dwm-${VERSION}.tar - rm -rf dwm-${VERSION} - -install: all - mkdir -p ~/.local - cp -f dwm ~/.local - chmod 755 ~/.local/dwm -# pkill dwm -# ~/.local/dwmblocks & - -uninstall: - rm -f ${DESTDIR}${PREFIX}/bin/dwm\ - ${DESTDIR}${MANPREFIX}/man1/dwm.1 - -.PHONY: all options clean dist install uninstall diff --git a/suckless/dwm/README b/suckless/dwm/README new file mode 100644 index 00000000..95d4fd05 --- /dev/null +++ b/suckless/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/suckless/dwm/README.es.org b/suckless/dwm/README.es.org deleted file mode 100644 index 3143644a..00000000 --- a/suckless/dwm/README.es.org +++ /dev/null @@ -1,32 +0,0 @@ -* Dynamic Window Manager - -Este es mi propio build de DWM, con algunos parches y configuraciones. - -*** Parches - -**** Funcionales -Aquellos parches que añaden nuevas funciones a DWM, algunas de ellas son funciones sencillas que están presentes en otros TWM. -- [[https://dwm.suckless.org/patches/actualfullscreen/dwm-actualfullscreen-20191112-cb3f58a.diff][actualfullscreen:]] Permite activar verdadera pantalla completa en lugar de solo activar el modo monocle y esconder el panel. -- [[https://dwm.suckless.org/patches/alwayscenter/][alwayscenter]]: Las ventanas flotantes siempre se colocan al centro de la pantalla. -- [[https://dwm.suckless.org/patches/cyclelayouts/dwm-cyclelayouts-20180524-6.2.diff][cyclelayouts:]] Pasa por la lista de layouts con una combinación de botones. -- [[https://dwm.suckless.org/patches/inplacerotate/][inplacerotate]]: Permite rotar las ventanas en el stack sin cambiar master. -- [[https://dwm.suckless.org/patches/movestack/dwm-movestack-6.1.diff][movestack:]] Permite mover las ventanas en la parte stack, cuando se usa el esquema por defecto. -- [[https://dwm.suckless.org/patches/pertag/dwm-pertag-20170513-ceac8c9.diff][pertag:]] Por defecto, dwm usa el mismo esquema para todos los tags. Con este parche cada tag tiene un esquema diferente (el esquema inicial es tile). -- [[https://dwm.suckless.org/patches/switchcol/][switchcol:]] Permite cambiar el foco entre master y stack con un solo /keybinding/. Útil con el layout /deck/. -- [[https://dwm.suckless.org/patches/winview/][winview]]: Si están viendo varios tags a la vez, al presionar un /keybinding/ se cambia al tag de la ventana enfocada. - -**** Layouts -Son aquellas /layouts/ nuevas que he agregado a DWM. -- [[https://dwm.suckless.org/patches/centeredmaster/][centeredmaster:]] La ventana /master/ se coloca en el centro mientras las otras aparecen en rejilla alrededor. -- [[https://dwm.suckless.org/patches/deck/][deck:]] La parte /stack/ solo muestra una ventana a la vez. Si se usa con /inplacerotate/ es posible cambiar la ventana en el /stack/ sin mover /master/. -- [[https://dwm.suckless.org/patches/fibonacci/dwm-fibonacci-5.8.2.diff][fibonacci:]] Dos esquemas nuevos: spiral y dwindle (à la bspwm). -- [[https://dwm.suckless.org/patches/gridmode/dwm-gridmode-20170909-ceac8c9.diff][gridmode:]] Esquema de rejilla para. -- [[https://dwm.suckless.org/patches/rmaster/dwm-rmaster-6.1.diff][rmaster:]] Permite invertir el orden del esquema tile: master a la izquierda y stack a la derecha. - -**** Estéticos -Parches que unicamente sirven para mejorar el aspecto estético del WM y aportan poco o nada al aspecto funcional. -- [[https://dwm.suckless.org/patches/alttagsdecoration/][alttagsdecoration]]: Permite declarar íconos diferentes para cada tag cuando están ocupados. -- [[https://dwm.suckless.org/patches/colorbar/][colorbar]]: Añade esquemas de colores nuevos para cada sección del panel. -- [[https://github.com/ashish-yadav11/dwmblocks][dwmblocks]]: Agrega soporte para texto coloreado y poder presionar en los módulos. -- [[https://dwm.suckless.org/patches/alpha/dwm-fixborders-6.2.diff][fixborders]]: Arregla los bordes transparentes cuando se usa compton/picom. -- [[https://dwm.suckless.org/patches/uselessgap/dwm-uselessgap-6.2.diff][uselessgap:]] Añade separaciones inútiles entre ventanas. Apesar de no ser el único parche, si es el más sencillo de aplicar. diff --git a/suckless/dwm/README.md b/suckless/dwm/README.md new file mode 100644 index 00000000..fef9468b --- /dev/null +++ b/suckless/dwm/README.md @@ -0,0 +1,690 @@ +This dwm 6.2 (bb2e72, 2020-07-08) side project has a different take on dwm patching. It uses preprocessor directives to decide whether or not to include a patch during build time. Essentially this means that this build, for better or worse, contains both the patched _and_ the original code. The aim being that you can select which patches to include and the build will contain that code and nothing more. Due to the complexity of some of the patches dwm-flexipatch has diverged from mainstream dwm by making some core patches non-optional for maintenance reasons. For the classic dwm-flexipatch build refer to branch [dwm-flexipatch-1.0](https://github.com/bakkeby/dwm-flexipatch/tree/dwm-flexipatch-1.0). + +For example to include the `alpha` patch then you would only need to flip this setting from 0 to 1 in [patches.h](https://github.com/bakkeby/dwm-flexipatch/blob/master/patches.def.h): +```c +#define BAR_ALPHA_PATCH 1 +``` + +So if you have ever been curious about trying out dwm, but have been discouraged by manual patching, then this may be a good starting point to see what a "fully fledged" dwm can look like. Want to try out the `pertag` patch? Just flip a config and recompile. Once you have found out what works for you and what doesn't then you should be in a better position to choose patches should you want to start patching from scratch. + +Alternatively if you have found the patches you want, but don't want the rest of the flexipatch entanglement on your plate then you may want to have a look at [flexipatch-finalizer](https://github.com/bakkeby/flexipatch-finalizer); a custom pre-processor tool that removes all the unused flexipatch code leaving you with a build that contains the patches you selected. + +Refer to [https://dwm.suckless.org/](https://dwm.suckless.org/) for details on the dwm window manager, how to install it and how it works. + +--- + +### Changelog: + +2021-02-11 - Added the riodraw and focusdir patches + +2021-01-22 - Added the placemouse patch + +2021-01-02 - Added the Layoutmenu patch + +2020-10-26 - Added the \_NET\_CLIENT\_LIST\_STACKING patch + +2020-09-29 - Added the on\_empty\_keys patch (ported from InstantOS) + +2020-09-28 - Added the \_IS\_FLOATING patch (embedded in the EWMHTAGS patch) + +2020-09-18 - Added the nomodbuttons patch allowing for toggleable mouse button bindings that have no modifiers + +2020-09-10 - Added the anybar patch (with experimental support for dwm bar(s) + anybar) + +2020-09-09 - Added the bar border patch + +2020-09-08 - Added ipc v1.5.5 patch + +2020-09-07 - Scratchpads improvement (multi-monitor support) + +2020-09-05 - Assortment of fullscreen improvements + +2020-08-27 - Added aspectresize patch + +2020-08-25 - Unified tag icon handling while adding support for different icons per monitor. Added alttagsdecoration patch. + +2020-08-22 - Added logic to auto-hide bars if nothing is drawn on them (e.g. for standalone bars that only show certain clients). Added clientindicators patch and unified indicator code. Simplified Pango integration by settling on common function signatures. + +2020-08-21 - Simplification of color configuration; settling on a set of color schemes that is shared between multiple patches (urgentborder, floatborder and titlecolor patches made non-optional) + +2020-08-20 - Added experimental flexwintitle patch based on bartabgroups + +2020-08-13 - Added bartabgroups patch + +2020-08-11 - Added decoration hints and focusmaster patches + +2020-08-10 - Added cool autostart, insets and steam patches + +2020-08-02 - Added reorganizetags patch + +2020-07-19 - Added barmodules patch - making extrabar, leftlayout, staticstatus and statusallmons patches redundant, added powerline patch + +2020-07-18 - **Note**: Up until now building dwm-flexipath without any patches selected would have given you something more or less identical with mainstream dwm. In order to reduce complexity when it comes to maintainance future versions of dwm-flexipatch may diverge from this by making some patches non-optional. For the classic dwm-flexipatch and its many patch integration hints refer to branch [dwm-flexipatch-1.0](https://github.com/bakkeby/dwm-flexipatch/tree/dwm-flexipatch-1.0) which will be subject to bug fixes and mainstream dwm updates as far as feasible. + +2020-07-05 - Extrabar compatibility improvements (staticstatus, status2d, dwmblocks) and fix for systray randomly causing dwm to crash when first systray application starts + +2020-06-24 - Added resizepoint, statusbutton and sendmon_keepfocus patches + +2020-06-21 - Added floatpos and bar_height patches + +2020-06-19 - Added tagothermonitor patch + +2020-06-15 - Added sizehints patch + +2020-06-14 - Added RULE macro to replace rules setup making the default config less of an abomination and making it simpler to include new rules based patches + +2020-06-11 - Added the pango patch + +2020-06-10 - Added the staticstatus patch + +2020-05-31 - Added the keymodes patch + +2020-05-29 - Added the color emoji patch + +2020-05-26 - Added the status2d patch (with alpha, systray, statuspadding and dwmblocks compatibility, no statuscolors or extrabar compatibility) + +2020-05-21 - Added the moveplace and moveresize patches + +2020-05-03 - Added the shiftviewclients patch and the no transparent borders patch which removes opacity from window borders when the alpha patch is not used + +2020-05-02 - Added dwmblocks patch + +2020-04-27 - Upgraded the tagmonfixfs patch to better support moving fullscreen windows to adjacent monitors + +2020-04-26 - Expanded monitor rules patch to include nmaster, showbar and topbar options + +2020-04-23 - Improved swallow and switchtag compatibility + +2020-04-16 - Upgraded the scratchpad patch to the multiple scratchpads patch \[[ref](https://lists.suckless.org/hackers/2004/17205.html)\]. Updated the statuscolors patch with the width computation fix \[[ref](https://lists.suckless.org/hackers/2004/17207.html)\]. + +2020-04-13 - Added statuscmd patch + +2020-03-31 - Added the rounded corners patch + +2020-03-27 - Revamped the dragmfact patch to support both horizontal and vertical layout splits as well as centered master variants + +2020-03-25 - Added dragcfact patch + +2020-03-23 - Added stacker patch + +2020-03-21 - Reworked a series of layouts to re-allocate remaining pixels following an even (or cfacts) split with the aim of presenting a pixel perfect layout. This affects the following layouts: tile, bstack, bstackhoriz, centered master, centered floating master, columns, deck, and corresponding flextile-deluxe layouts + +2020-02-11 - Added swaptags and vtcolor patches + +2020-02-09 - Added alternative scratchpad patch + +2020-02-02 - Added fsignal and transferall patches + +2020-01-29 - Added swapfocus and shiftview patches + +2020-01-26 - Added transfer patch + +2020-01-24 - Added barpadding patch (incl. statusallmons, statuspadding, statuscolors, systray, alpha, holdbar and extrabar patch compatibility). Moved patches.h to patches.def.h to mimic the config pattern of having default and personal settings. + +2020-01-17 - Added inplacerotate patch + +2019-12-15 - Updated dragmfact patch to include fix patch to make it work with multiple monitors + +2019-11-26 - Added dmenumatchtop patch, added improvements to the switchtag patch based on ideas from the switchtotag patch + +2019-11-21 - Added fakefullscreenclient patch + +2019-10-24 - Added dragmfact, extrabar, exresize and nodmenu patches + +2019-10-22 - Added ispermanent and swallow patches + +2019-10-16 - Introduced [flexipatch-finalizer](https://github.com/bakkeby/flexipatch-finalizer) + +2019-10-11 - Added the patch to ignore Xft errors when drawing text in the status bar + +2019-10-10 - Added mpdcontrol, scratchpad and spawn_cwd cpatches + +2019-10-08 - Added columns layout and fakefullscreen patch + +2019-10-07 - Added sortscreens and dwmc patches, fixed minor cross-compatibility issues for combo, holdbar, leftlayout, hidevacanttags, taggrid and activetagindicatorbar + +2019-10-06 - Added statuscolors and statusallmons patches, fixed minor cross-compatibility issues for killunsel, fullscreen, noborder, tagintostack patches + +2019-10-05 - Added killunsel, taggrid, hidevacanttags and cmdcustomize patches + +2019-10-04 - Added maximize, movestack, monoclesymbol, noborder, tagall and tagintostack patches + +2019-10-03 - Added onlyquitonempty and switchcol patches + +2019-10-02 - Added restartsig, emptyview, focusurgent and focusadjacenttag patches + +2019-10-01 - Added leftlayout, fullscreen, holdbar and unfloatvisible patches + +2019-09-30 - Replaced flextile with flextile-deluxe, refactored monitor rules to support predetermined layouts per tag + +2019-09-15 - Added focusonclick, xrdb, viewontag, urgentborder and winview patches + +2019-09-14 - Added setborderpx, selfrestart and push (no master variant), sticky and warp patches + +2019-09-13 - Added titlecolor and push patches + +2019-09-12 - Added activetagindicatorbar, alwaysfullscreen and autoresize patches + +2019-09-11 - Added monitor rules, combo and ewmhtags patches + +2019-09-10 - Minor tweaks to awesomebar patch (incl. alpha and systray compatibility). Added floatbordercolor patch. + +2019-09-09 - Added deck, fibonacci (dwindle and spiral), gridmode, gapplessgrid, horizgrid, nrowgrid, centeredmaster and flextile layouts. Added alternativetags and awesomebar patches. + +2019-09-08 - Added cfacts and vanitygaps patches, added bstack and bstackhoriz layouts + +2019-09-07 - Added cyclelayouts, resizecorners, rotatestack, savefloats, statuspadding, switchtag, center and windowrolerule patches + +2019-09-06 - Added attachabove, attachaside, attachbelow, attachbottom, autostart, fancybar, focusonnetactive and losefullscreen patches + +2019-09-05 - Alpha, systray, togglefullscreen, tagallmon, tagmonfixfs, tagswapmon, pertag and zoomswap patches added + +### Patches included: + + - [activetagindicatorbar](https://dwm.suckless.org/patches/activetagindicatorbar/) + - this patch changes the rectangle indicating if a tag is used by a client into a bar above the tag name + + - [alpha](https://dwm.suckless.org/patches/alpha/) + - adds transparency for the status bar + + - [alternativetags](https://dwm.suckless.org/patches/alternativetags/) + - adds alternative tags which can be toggled on the fly for the sole purpose of providing visual aid + + - [alttagsdecoration](https://dwm.suckless.org/patches/alttagsdecoration/) + - provides the ability to use alternative text for tags which contain at least one window + + - [alwaysfullscreen](https://dwm.suckless.org/patches/alwaysfullscreen/) + - prevents the focus to drift from the active fullscreen client when using focusstack\(\) + + - [anybar](https://dwm.suckless.org/patches/anybar/) + - enables dwm to manage external status bars such as lemonbar and polybar + - dwm treats the external bar as it would its own, so all regular dwm commands such as togglebar affect the external bar in the same way + + - [aspectresize](https://dwm.suckless.org/patches/aspectresize/) + - allows windows to be resized with its aspect ratio remaining constant + + - [attachabove](https://dwm.suckless.org/patches/attachabove/) + - new windows are placed above selected client + + - [attachaside](https://dwm.suckless.org/patches/attachaside/) + - new windows are placed on top of the stack + + - [attachbelow](https://dwm.suckless.org/patches/attachbelow/) + - new windows are placed below selected client + + - [attachbottom](https://dwm.suckless.org/patches/attachbottom/) + - new windows are placed at the bottom of the stack + + - [autoresize](https://dwm.suckless.org/patches/autoresize/) + - by default, windows that are not visible when requesting a resize/move will not get resized/moved, with this patch, however, they will + + - [autostart](https://dwm.suckless.org/patches/autostart/) + - makes dwm run `~/.dwm/autostart_blocking.sh` and `~/.dwm/autostart.sh &` on startup + + - [awesomebar](https://dwm.suckless.org/patches/awesomebar/) + - enhanced taskbar that allows focus / hiding / unhiding of windows by clicking on the status bar + + - [bar_border](https://codemadness.org/paste/dwm-border-bar.patch) + - adds a border around the bar similarly to how client windows have borders + + - [bar_height](https://dwm.suckless.org/patches/bar_height/) + - allows the bar height to be explicitly set rather than being derived from font + + - [barmodules](https://github.com/bakkeby/patches/wiki/barmodules/) + - splits the dwm bar into modules allowing for re-arrangement of the bar and easier integration for new features + + - [barpadding](https://dwm.suckless.org/patches/barpadding/) + - adds vertical and horizontal space between the statusbar and the edge of the screen + + - [bartabgroups](https://dwm.suckless.org/patches/bartabgroups/) + - turns the titlebar area into a mfact-respecting tab-bar showing each client's title + + - [center](https://dwm.suckless.org/patches/center/) + - adds an iscentered rule to automatically center clients on the current monitor + + - [cfacts](https://dwm.suckless.org/patches/cfacts/) + - the cfacts patch provides the ability to assign different weights to clients in their respective stack in tiled layout + + - [clientindicators](https://dwm.suckless.org/patches/clientindicators/) + - draws a dot indicator overlayed on each tag icon for each client + - the selected client is drawn as a larger horizontal line + + - [cmdcustomize](https://dwm.suckless.org/patches/cmdcustomize/) + - allows color attributes to be set through the command line + + - [colorbar](https://dwm.suckless.org/patches/colorbar/) + - lets you change the foreground and background color of every statusbar element + + - color_emoji + - enables color emoji in dmenu by removing a workaround for a BadLength error in the Xft library when color glyphs are used + - enabling this will crash dwm on encountering such glyphs unless you also have an updated Xft library that can handle them + + - [combo](https://dwm.suckless.org/patches/combo/) + - allows you to select multiple tags by pressing all the right keys as a combo, e.g. hold MOD and press and hold 1 and 3 together to view those two tags + + - [cool_autostart](https://dwm.suckless.org/patches/cool_autostart/) + - allows dwm to execute commands from an array in the config.h file + - when dwm exits all processes from the autostart array will be killed automatically + + - [cyclelayouts](https://dwm.suckless.org/patches/cyclelayouts/) + - lets you cycle through all your layouts + + - [decoration_hints](https://dwm.suckless.org/patches/decoration_hints/) + - make dwm respect \_MOTIF\_WM\_HINTS property, and not draw borders around windows requesting for it + - some applications use this property to notify window managers to not draw window decorations + - not respecting this property leads to issues with applications that draw their own borders, like chromium (with "Use system title bar and borders" turned off) or vlc in fullscreen mode + + - [dmenumatchtop](https://dwm.suckless.org/patches/dmenumatchtop) + - updates the position of dmenu to match that of the bar + - i.e. if topbar is 0 then dmenu will appear at the bottom and if 1 then dmenu will appear at the top + + - [dragcfact](https://github.com/bakkeby/patches/wiki/dragcfact/) + - lets you resize clients' size (i.e. modify cfact) by holding modkey + shift + right-click and dragging the mouse + + - [dragmfact](https://github.com/bakkeby/patches/wiki/dragmfact/) + - lets you resize the split in layouts (i.e. modify mfact) by holding the modkey + shift + left-click and dragging the mouse + - this is a bespoke patch that supports vertical and horizontal layout splits as well as centered master variants + + - [dwmblocks](https://gist.github.com/danbyl/54f7c1d57fc6507242a95b71c3d8fdea) + - signal integration to use dwm with a patched [dwmblocks](https://github.com/torrinfail/dwmblocks) + - combined with the statuscmd patch this gives a clickable statusbar + + - [dwmc](http://dwm.suckless.org/patches/dwmc/) + - a simple dwmc client using a fork of fsignal to communicate with dwm + + - [emptyview](https://dwm.suckless.org/patches/emptyview/) + - allows no tag at all to be selected + - dwm will start with no tag selected and when a client with no tag rule is started and no tag is selected then it will be opened on the first tag + + - [ewmhtags](https://dwm.suckless.org/patches/ewmhtags/) + - adds EWMH support for \_NET_NUMBER_OF_DESKTOPS, \_NET_CURRENT_DESKTOP, \_NET_DESKTOP_NAMES and \_NET_DESKTOP_VIEWPORT, which allows for compatibility with other bars and programs that request workspace information, e.g. polybar's xworkspaces module + + - [exresize](https://dwm.suckless.org/patches/exresize/) + - this patch allows the user to change size and placement of floating windows using only the keyboard + - it also allows for temporary vertical and horizontal extension of windows similar to other WMs fill command + + - [~extrabar~](https://dwm.suckless.org/patches/extrabar/) + - ~enables an extra status bar in dwm in a similar manner to the dualstatus patch~ + - ~if the primary status is at the top via topbar then the extra status bar will be placed at the bottom and vice versa~ + + - extrastatus + - formerly extrabar - now only splits the status into to statuses by using a status separator + + - [fakefullscreen](https://dwm.suckless.org/patches/fakefullscreen/) + - only allow clients to "fullscreen" into the space currently given to them + - as an example, this will allow you to view a fullscreen video in your browser on one half of the screen, while having the other half available for other tasks + + - [fakefullscreenclient](https://github.com/bakkeby/patches/wiki/fakefullscreenclient/) + - similarly to the fakefullscreen patch this patch only allows clients to "fullscreen" into the space currently given to them + - as an example, this will allow you to view a fullscreen video in your browser on one half of the screen, while having the other half available for other tasks + - the "twist" with this patch is that fake fullscreen can be toggled on a per client basis rather than applying to all clients globally + + - [fancybar](https://dwm.suckless.org/patches/fancybar/) + - shows the titles of all visible windows in the status bar + + - flexwintitle + - based on the bartabgroups patch, this is a layout aware barmodules module for handling window titles intended to be used with flextile-deluxe + + - [~floatbordercolor~](https://dwm.suckless.org/patches/float_border_color/) + - ~this patch allows a different border color to be chosen for floating windows~ + + - [floatpos](https://github.com/bakkeby/patches/wiki/floatpos/) + - adds a float rule allowing the size and position of floating windows to be specified + - control the size and position of floating windows similar to exresize, moveresize, moveplace patches + - specify size and position using absolute, relative or fixed co-ordinates or + - position floating windows in a grid-like manner + + - [focusadjacenttag](https://dwm.suckless.org/patches/focusadjacenttag/) + - provides the ability to focus the tag on the immediate left or right of the currently focused tag + - it also allows to send the focused window either on the left or the right tag + + - [focusdir](https://github.com/bakkeby/patches/wiki/focusdir) + - allows focusing on clients based on direction (up, down, left, right) instead of client order + + - [focusmaster](https://dwm.suckless.org/patches/focusmaster/) + - a simple patch that just puts focus back to the master client + + - [focusonclick](https://dwm.suckless.org/patches/focusonclick/) + - this patch makes you switch focus only by mouse click and not sloppy (focus follows mouse pointer) + + - [focusonnetactive](https://dwm.suckless.org/patches/focusonnetactive/) + - by default, dwm responds to \_NET_ACTIVE_WINDOW client messages by setting the urgency bit on the named window + - this patch activates the window instead + + - [focusurgent](https://dwm.suckless.org/patches/focusurgent/) + - adds a keyboard shortcut to select the next window having the urgent flag regardless of the tag it is on + + - [fsignal](https://dwm.suckless.org/patches/fsignal/) + - send "fake signals" to dwm for handling, using xsetroot + - this will not conflict with the status bar, which also is managed using xsetroot + + - [fullscreen](https://dwm.suckless.org/patches/fullscreen/) + - applies the monocle layout with the focused client on top and hides the bar + - when pressed again it shows the bar and restores the layout that was active before going fullscreen + + - [hidevacanttags](https://dwm.suckless.org/patches/hide_vacant_tags/) + - prevents dwm from drawing tags with no clients (i.e. vacant) on the bar + + - [holdbar](http://dwm.suckless.org/patches/holdbar/) + - with this patch dwm's built-in status bar is only shown when HOLDKEY is pressed + - additionally the bar will now overlay the display + + - [ignore-xft-errors-when-drawing-text](https://groups.google.com/forum/m/#!topic/wmii/7bncCahYIww) + - sometimes dwm crashes when it cannot render some glyphs in window titles (usually emoji) + - this patch is essentially a hack to ignore any errors when drawing text on the status bar and may be removed if a more appropriate solution comes up + + - [inplacerotate](https://dwm.suckless.org/patches/inplacerotate/) + - allows rotation of all clients in the master or stack area without affecting the other area + + - [insets](https://dwm.suckless.org/patches/insets/) + - lets custom insets from each edge of the screen to be defined + - an example use case would be to make space for an external bar + + - [ipc](https://github.com/mihirlad55/dwm-ipc) + - implements inter-process communication through a UNIX socket for dwm + - allows for the window manager to be queried for information, e.g. listen for events such as tag or layout changes, as well as send commands to control the window manager via other programs + + - [\_IS\_FLOATING](https://github.com/bakkeby/dwm-flexipatch/issues/50) + - adds the \_IS\_FLOATING xproperty for floating windows + - this can allow for a compositor to handle floating windows differently to tiled windows, e.g. only show shadows on floating windows + - this patch is enabled via the ewmhtags patch + + - [ispermanent](https://dwm.suckless.org/patches/ispermanent/) + - adds rule option for clients to avoid accidental termination by killclient for sticky windows + + - [keymodes](https://dwm.suckless.org/patches/keymodes/) + - this patch adds key modes (like in vim or emacs) where chains of keyboard shortcuts can be performed + + - [~leftlayout~](http://dwm.suckless.org/patches/leftlayout/) + - ~moves the layout symbol in the status bar to the left hand side~ + + - [losefullscreen](https://github.com/bakkeby/patches/wiki/losefullscreen/) + - by default in dwm it is possible to make an application fullscreen, then use the focusstack keybindings to focus on other windows beneath the current window + - it is also possible to spawn new windows (e.g. a terminal) that end up getting focus while the previous window remains in fullscreen + - this patch ensures that in such scenarios the previous window loses fullscreen + + - [maximize](https://dwm.suckless.org/patches/maximize/) + - adds helper functions for maximizing, horizontally and vertically, floating windows using keybindings + + - [mpdcontrol](https://dwm.suckless.org/patches/mpdcontrol/) + - adds keyboard bindings to control MDP (Music Player Daemon) + + - [monitorrules](https://github.com/bakkeby/patches/wiki/monitorrules/) + - adds rules per monitor, e.g. have default layouts per monitor + - the use case for this is if the second monitor is vertical (i.e. rotated) then you may want to use a different default layout for this monitor than what is used for the main monitor (for example normal vertical split for main monitor and horizontal split for the second) + + - [monoclesymbol](https://dwm.suckless.org/patches/monoclesymbol/) + - always display the the monocle-symbol as defined in config.h if the monocle-layout is activated + - do not display the number of open clients in the current tag + + - [moveresize](https://dwm.suckless.org/patches/moveresize/) + - allows you to move and resize dwm's clients using keyboard bindings + + - [movestack](https://dwm.suckless.org/patches/movestack/) + - allows you to move clients around in the stack and swap them with the master + + - [netclientliststacking](https://github.com/bakkeby/patches/wiki/netclientliststacking) + - adds support for the \_NET\_CLIENT\_LIST\_STACKING atom, needed by certain applications like the Zoom video conferencing application + + - [noborder](https://dwm.suckless.org/patches/noborder/) + - removes the border when there is only one window visible + + - [nodmenu](https://dwm.suckless.org/patches/nodmenu/) + - enable modifying dmenu in config.def.h which resulted previously in a compilation error because two lines of code hardcode dmenu into dwm + - allows complete removal of dmenu, should you want to do that + + - nomodbuttons + - allows for toggleable client button bindings that have no modifiers + - this can, for example, allow you to move or resize using the mouse alone without holding down a modifier key, which can be practical if you have extra buttons on your mouse + + - [no_transparent_borders](https://github.com/szatanjl/dwm/commit/1529909466206016f2101457bbf37c67195714c8) + - when terminals have transparency then their borders also become transparent + - this patch ensures that borders have no transparency + - note that this patch is only relevant if you are not using the alpha patch + + - [on\_empty\_keys](https://github.com/bakkeby/dwm-flexipatch/issues/51) + - port of InstantVM's on_empty_keys functionality allowing keybindings that apply only when a tag/view is empty + - an example use case is being able to launch applications with first hand keys like "f" to launch firefox + + - [onlyquitonempty](https://dwm.suckless.org/patches/onlyquitonempty/) + - makes it so dwm will only exit via quit() if no windows are open (in order to prevent accidental loss of work) + + - [pango](https://dwm.suckless.org/patches/pango/) + - adds simple markup for status messages using pango markup + + - [pertag](https://dwm.suckless.org/patches/pertag/) + - adds nmaster, mfact, layouts and more per tag rather than per monitor + + - [placemouse](https://github.com/bakkeby/patches/wiki/placemouse) + - lets the user change the position of a client in the stack using the mouse. + + - [powerline](https://gitlab.com/udiboy1209-suckless/dwm/-/commit/071f5063e8ac4280666828179f92788d893eea40#4b1a539194be7467cefbda22f675a3b7c19ceca7) + - adds drawing of powerline arrows (and diagonal lines) for both the status bar and the tags + + - [push](https://dwm.suckless.org/patches/push/) + - this patch provides a way to move clients up and down inside the client list + + - [reorganizetags](https://dwm.suckless.org/patches/reorganizetags/) + - shifts all clients per tag to leftmost unoccupied tags + - e.g. if clients A, B, C are tagged on tags 1, 5, 9 respectively, when reorganized they will now be on tag 1, 2, and 3 + + - [resizecorners](https://dwm.suckless.org/patches/resizecorners/) + - by default, windows only resize from the bottom right corner + - with this patch the mouse is warped to the nearest corner and you resize from there + + - [resizepoint](https://github.com/bakkeby/patches/wiki/resizepoint/) + - practically the same as resizecorners, but the cursor does not warp to any of the window corners + + - [restartsig](https://dwm.suckless.org/patches/restartsig/) + - adds a keyboard shortcut to restart dwm or alternatively by using kill -HUP dwmpid + - additionally dwm can quit cleanly by using kill -TERM dwmpid + + - [riodraw](https://github.com/bakkeby/patches/wiki/riodraw/) + - adds rio-like drawing to spawn new windows or to resize the selected client (backported from instantWM) + - depends on an external tool slop being installed + + - [rotatestack](https://dwm.suckless.org/patches/rotatestack/) + - let's you rotate through the stack using keyboard shortcuts + + - [roundedcorners](https://github.com/mitchweaver/suckless/blob/master/dwm/patches/mitch-06-rounded_corners-f04cac6d6e39cd9e3fc4fae526e3d1e8df5e34b2.patch) + - adds rounded corners to client windows + + - [savefloats](https://dwm.suckless.org/patches/save_floats/) + - saves size and position of every floating window before it is forced into tiled mode + - if the window is made floating again then the old dimensions will be restored + + - [scratchpad](https://dwm.suckless.org/patches/scratchpad/) + - the scratchpad patch allows you to spawn or restore a floating terminal window + + - [scratchpad_alt_1](https://github.com/GasparVardanyan/dwm-scratchpad) + - this alternative patch enables a scratchpad feature in dwm similar to the scratchpad feature in i3wm + + - [selfrestart](https://dwm.suckless.org/patches/selfrestart/) + - restart dwm without the unnecessary dependency of an external script + + - [sendmon_keepfocus](https://github.com/bakkeby/patches/wiki/sendmon_keepfocus/) + - minor patch that allow clients to keep focus when being sent to another monitor + + - [setborderpx](https://dwm.suckless.org/patches/setborderpx/) + - this patch allows border pixels to be changed during runtime + + - [shiftview](https://github.com/chau-bao-long/dotfiles/blob/master/suckless/dwm/shiftview.diff) + - adds keybindings for left and right circular shift through tags + - also see focusadjacenttag + + - [shiftviewclients](https://github.com/bakkeby/patches/wiki/shiftviewclients/) + - variant of the shiftview patch which skips tags that have no clients + + - [sizehints](https://dwm.suckless.org/patches/sizehints/) + - makes dwm obey even "soft" sizehints for new clients + + - [sortscreens](https://www.mail-archive.com/hackers@suckless.org/msg09400.html) + - this patch aims to address some inconsistencies when it comes to focusmon, tagmon and similar functionality by explicitly sorting screens left to right (or top to bottom in a vertical layout) + + - [spawn_cwd](https://dwm.suckless.org/patches/spawn_cwd/) + - spawns programs from currently focused client's working directory + + - [stacker](https://dwm.suckless.org/patches/stacker/) + - provides comprehensive utilities for managing the client stack + + - [~staticstatus~](https://dwm.suckless.org/patches/staticstatus/) + - ~allows the status text to be fixed to the bar on a specific monitor rather than being drawn on the focused monitor~ + + - [status2d](https://dwm.suckless.org/patches/status2d/) + - allows colors and rectangle drawing in the dwm status bar + + - [~statusallmons~](https://dwm.suckless.org/patches/statuspadding/) + - ~this patch draws and updates the statusbar on all monitors~ + + - [statusbutton](https://dwm.suckless.org/patches/statusbutton/) + - adds a clickable button to the left hand side of the statusbar + + - [statuscmd](https://dwm.suckless.org/patches/statuscmd/) + - adds the ability to execute shell commands based on the mouse button and position when clicking the status bar + + - [statuscolors](https://dwm.suckless.org/patches/statuscolors/) + - enables colored text in the status bar allowing multiple color combinations for use in the status script + + - [statuspadding](https://dwm.suckless.org/patches/statuspadding/) + - adds configuration options for horizontal and vertical padding in the status bar + + - [steam](https://github.com/bakkeby/patches/wiki/steam) + - a minor patch that works around the issue of floating Steam windows jumping around the screen when they receive focus + + - [sticky](https://dwm.suckless.org/patches/sticky/) + - adds toggleable keyboard shortcut to make a client 'sticky', i.e. visible on all tags + + - [swallow](https://dwm.suckless.org/patches/swallow/) + - this patch adds "window swallowing" to dwm as known from Plan 9's windowing system rio + - clients marked with isterminal in config.h swallow a window opened by any child process, e.g. running xclock in a terminal + - closing the xclock window restores the terminal window in the current position + + - [swapfocus](https://dwm.suckless.org/patches/swapfocus/) + - this patch depends on the pertag patch and makes it possible to switch focus with a single shortcut (mod-s) instead of having to think if you should use mod-j or mod-k for reaching the previously used window + + - [swaptags](https://dwm.suckless.org/patches/swaptags/) + - allows swapping the contents of the currently selected tag with another tag by using keyboard shortcuts + + - [switchcol](https://dwm.suckless.org/patches/switchcol/) + - allows you to switch focus between the master and stack columns using a single keybinding + + - [switchtag](https://github.com/bakkeby/patches/wiki/switchtag/) + - when an application opens on a specific tab this patch adds the option to also switch to that tag when the application starts + - optionally, the previous view can also be restored when the client is closed + + - [systray](https://dwm.suckless.org/patches/systray/) + - adds system tray in the status bar + + - [tagall](https://dwm.suckless.org/patches/tagall/) + - adds keyboard shortcuts to move all (or only floating) windows from one tag to another + + - [tagallmon](https://github.com/bakkeby/patches/wiki/tagallmon/) + - move all visible windows to an adjacent monitor + + - [tagintostack](https://dwm.suckless.org/patches/tagintostack/) + - makes new clients attach into the stack area when you toggle a new tag into view + - this means your master area will remain unchanged when toggling views + + - [taggrid](https://dwm.suckless.org/patches/taggrid/) + - adds an option to place tags in rows like in many other window managers + + - [tagmonfixfs](https://github.com/bakkeby/patches/wiki/tagmonfixfs/) + - allows moving a fullscreen window to another monitor while remaining in fullscreen + + - [tagothermonitor](https://dwm.suckless.org/patches/tagothermonitor/) + - adds functions and keybindings to tag a window to a desired tag on an adjacent monitor + + - [tagswapmon](https://github.com/bakkeby/patches/wiki/tagswapmon/) + - swap all visible windows on one monitor with those of an adjacent monitor + + - [~titlecolor~](https://dwm.suckless.org/patches/titlecolor/) + - ~adds a new color scheme used by the (selected) window title in the bar~ + + - [togglefullscreen](https://github.com/bakkeby/patches/wiki/togglefullscreen/) + - allows you to toggle fullscreen on and off using a single shortcut key + + - [transfer](https://dwm.suckless.org/patches/transfer/) + - lets you transfer the currently focused client between the master and stack area while increasing or decreasing the master area (nmaster) accordingly + + - [transferall](https://dwm.suckless.org/patches/transfer/) + - lets you transfer all clients between the master and stack area while increasing or decreasing the master area (nmaster) accordingly + + - [unfloatvisible](https://dwm.suckless.org/patches/unfloatvisible/) + - resets isfloating on any visible windows that have it set and optionally also applies a layout + + - [killunsel](https://dwm.suckless.org/patches/killunsel/) + - kills all visible clients that are not selected (only the selected client will remain) + + - [~urgentborder~](https://dwm.suckless.org/patches/urgentborder/) + - ~this patch makes "urgent" windows have different colors~ + + - [vanitygaps](https://github.com/bakkeby/patches/blob/master/dwm/dwm-vanitygaps-6.2.diff) + - adds configurable gaps between windows differentiating between outer, inner, horizontal and vertical gaps + + - [viewontag](https://dwm.suckless.org/patches/viewontag/) + - follow a window to the tag it is being moved to + + - [vtcolor](https://dwm.suckless.org/patches/vtcolors/) + - this patch adds the ability for dwm to read colors from the linux virtual console essentially allowing you to use the same color scheme as your regular tty + + - [warp](https://dwm.suckless.org/patches/warp/) + - warps the mouse cursor to the center of the currently focused window or screen when the mouse cursor is (a) on a different screen or (b) on top of a different window + + - [windowrolerule](https://github.com/bakkeby/patches/wiki/windowrolerule/) + - sometimes a single application opens different windows depending on the task at hand and this is often reflected in the WM_WINDOW_ROLE(STRING) x property + - this patch adds the role field to the rule configuration so that one can differentiate between, say, Firefox "browser" vs "Preferences" vs "Manager" or Google-chrome "browser" vs "pop-up". + + - [winview](http://dwm.suckless.org/patches/winview/) + - allows switching the view to that of a given client from the all-window view (Mod-0) using a keyboard shortcut + + - [xrdb](http://dwm.suckless.org/patches/xrdb/) + - allows dwm to read colors from xrdb (.Xresources) during runtime + + - [zoomfloating](https://www.reddit.com/r/suckless/comments/ie5fe3/zoomfloating_my_own_simple_original_patch/) + - a simple patch that allows floating windows to be zoomed into the master stack position + + - [zoomswap](https://dwm.suckless.org/patches/zoomswap/) + - allows a master and a stack window to swap places rather than every window on the screen changing position + +### Layouts included: + + - [bstack](https://dwm.suckless.org/patches/bottomstack/) + - bottomstack layout + + - [bstackhoriz](https://dwm.suckless.org/patches/bottomstack/) + - bottomstack horizontal layout + + - [centeredmaster](https://dwm.suckless.org/patches/centeredmaster/) + - centeredmaster layout + + - [centeredfloatingmaster](https://dwm.suckless.org/patches/centeredmaster/) + - centeredfloatingmaster layout + + - [columns](https://dwm.suckless.org/patches/columns/) + - same as the default tile layout except clients in the master area are arranged in columns (i.e. left to right) + + - [deck](https://dwm.suckless.org/patches/deck/) + - deck layout - clients in the stack area are arranged on top of each other (like monocle) + + - [fibonacci](https://dwm.suckless.org/patches/fibonacci/) + - fibonacci (dwindle and spiral) layouts + + - [flextile-deluxe](https://github.com/bakkeby/patches/wiki/flextile-deluxe/) + - a re-envisioned, flexible and over-the-top version of the original [flextile](https://dwm.suckless.org/patches/flextile/) patch supporting + - multiple split layouts (horizontal, vertical, centered, floating, fixed) + - tile arrangement on a per split basis (stack horizontally, stack vertically, grids, fibonacci) + - pertag, cfacts, rmaster, vanitygaps compatibility + - tile, deck, monocle, centeredmaster, bstack, bstackhoriz, gapplessgrid and more + - this gives you a lot of versatility in terms of layout + + - [gapplessgrid](https://dwm.suckless.org/patches/gaplessgrid/) + - gappless grid layout + + - [gridmode](https://dwm.suckless.org/patches/gridmode/) + - gridmode (grid) layout + + - [horizgrid](https://dwm.suckless.org/patches/horizgrid/) + - horizontal grid layout + + - [nrowgrid](https://dwm.suckless.org/patches/nrowgrid/) + - nrowgrid layout, number of rows in grid controlled by nmaster diff --git a/suckless/dwm/README.org b/suckless/dwm/README.org deleted file mode 100644 index ff375b26..00000000 --- a/suckless/dwm/README.org +++ /dev/null @@ -1,35 +0,0 @@ -#+TITLE:DWM: Dynamic Window Manager - -This is my own build of DWM with some patches and configurations. - -*** Patches - -**** Feature related -Those patches that add new features to DWM, some of them are simple features that are present in other TWMs. -- [[https://dwm.suckless.org/patches/actualfullscreen/dwm-actualfullscreen-20191112-cb3f58a.diff][actualfullscreen:]] Allows to activate true fullscreen instead of just change to monocle layout and hide the bar. -- [[https://dwm.suckless.org/patches/alwayscenter/][alwayscenter]]: Floating windows are always placed at the center of the screen. -- [[https://dwm.suckless.org/patches/cyclelayouts/dwm-cyclelayouts-20180524-6.2.diff][cyclelayouts:]] Go through the layout list with a button combination. -- [[https://dwm.suckless.org/patches/inplacerotate/][inplacerotate]]: Allows to rotate the windows in the stack without changing master. -- [[https://dwm.suckless.org/patches/movestack/dwm-movestack-6.1.diff][movestack:]] Allows to move the windows in the stack part, when using the default layout. -- [[https://dwm.suckless.org/patches/pertag/dwm-pertag-20170513-ceac8c9.diff][pertag:]] By default, dwm uses the same layout for all tags. With this patch each tag has a different layout (the initial scheme is tile). -- [[https://dwm.suckless.org/patches/switchcol/][switchcol:]] It allows to change the focus between master and stack with a single keybinding. Useful with the /deck/ layout. -- [[https://dwm.suckless.org/patches/winview/][winview]]: If you are seeing several tags at once, pressing a keybinding switches to the tag in the focused window. - -**** Layouts -New layout I've added to DWM. -- [[https://dwm.suckless.org/patches/centeredmaster/][centeredmaster:]] The /master/ window is placed in the center while the others appear in a grid around it. -- [[https://dwm.suckless.org/patches/deck/][deck:]] The /stack/ part only shows one window at a time. If used with /inplacerotate/ it is possible to change the window in /stack/ without moving /master/. -- [[https://dwm.suckless.org/patches/fibonacci/dwm-fibonacci-5.8.2.diff][fibonacci:]] Two new layouts: spiral y dwindle (à la bspwm). -- [[https://dwm.suckless.org/patches/gridmode/dwm-gridmode-20170909-ceac8c9.diff][gridmode:]] Grid layout. -- [[https://dwm.suckless.org/patches/rmaster/dwm-rmaster-6.1.diff][rmaster:]] Allows to reverse the order of the tile scheme: master on the left and stack on the right. - -**** Aesthetic related -Patches that only serve to improve the aesthetic aspect of the WM and contribute little or nothing to the functional aspect. - -- [[https://dwm.suckless.org/patches/alttagsdecoration/][alttagsdecoration]]: Allows you to declare different icons for each tag when they are busy. -- [[https://dwm.suckless.org/patches/barpadding/][barpadding:]] Add vertical andhorizontal padding to the bar from the screen. -- [[https://dwm.suckless.org/patches/colorbar/][colorbar]]: Add new color schemes for each section of the panel. -- [[https://github.com/ashish-yadav11/dwmblocks][dwmblocks]]: Add support for colored text and click on the dwmblocks modules. -- [[https://dwm.suckless.org/patches/alpha/dwm-fixborders-6.2.diff][fixborders]]: Fix the transparent borders when using compton/picom. -- [[https://dwm.suckless.org/patches/uselessgap/dwm-uselessgap-6.2.diff][uselessgap:]] Add useless gaps between windows. Although it is not the only patch, it is the easiest to apply. - diff --git a/suckless/dwm/config.bak b/suckless/dwm/config.bak new file mode 100644 index 00000000..dcd4b4e3 --- /dev/null +++ b/suckless/dwm/config.bak @@ -0,0 +1,33 @@ +/* See LICENSE file for copyright and license details. */ + +#include +/* appearance */ +static const int rmaster = 0; /* 1 = master at right*/ +static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ +static const unsigned int systrayspacing = 2; /* systray spacing */ +static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ +static const int showsystray = 1; /* 0 means no systray */ +static const int tag_padding = 0; +static const int vertpad = 0; /* vertical padding of bar */ +static const int sidepad = 0; /* horizontal padding of bar */ + +/* tagging */ +static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"}; +//static const char *alttags[] = { "󰄯", "󰄯", "󰄯", "󰄯"}; + +/* layout(s) */ +static const float mfact = 0.5; /* factor of master area size [0.05..0.95] */ +static const int nmaster = 1; /* number of clients in master area */ +static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */ + +static const Layout layouts[] = { + /* symbol arrange function */ + { "鉶", tile }, /* first entry is default */ +/* { "", dwindle }, */ + { "ﱖ", grid }, + { "", centeredmaster }, + { "", centeredfloatingmaster }, + { "[M]", monocle }, + { "[D]", deck }, + { NULL, NULL }, +}; diff --git a/suckless/dwm/config.h b/suckless/dwm/config.h index 5aa73d72..cddbec5d 100644 --- a/suckless/dwm/config.h +++ b/suckless/dwm/config.h @@ -2,262 +2,53 @@ #include /* appearance */ -static const unsigned int borderpx = 3; /* border pixel of windows */ -static const unsigned int gappx = 6; -static const unsigned int snap = 32; /* snap pixel */ -static const int rmaster = 0; /* 1 = master at right*/ -static const int showbar = 1; /* 0 means no bar */ +static const int rmaster = 0; /* 1 = master at right*/ static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ static const unsigned int systrayspacing = 2; /* systray spacing */ static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ -static const int showsystray = 1; /* 0 means no systray */ -static const int topbar = 1; /* 0 means bottom bar */ -static const int user_bh = 27; /* 0 means that dwm will calculate bar height, >= 1 means dwm will user_bh as bar height */ -static const int tag_padding = 0; -static const int vertpad = 0; /* vertical padding of bar */ -static const int sidepad = 0; /* horizontal padding of bar */ -static const char *fonts[] = {"Hack Nerd Font:Regular:size=10", "Material Design Icons:Regular:pixelsize=16:antialias=true"}; -static const char dmenufont[] = "Hack Nerd Font:size=10"; -static const char fore[] = "#f8f8f2"; -static const char back[] = "#282a36"; -static const char border[] = "#f8f8f2"; -static const char col0[] = "#000000"; -static const char col1[] = "#FF5555"; -static const char col2[] = "#50FA7B"; -static const char col3[] = "#F1FA8C"; -static const char col4[] = "#BD93F9"; -static const char col5[] = "#FF79C6"; -static const char col6[] = "#8BE9FD"; -static const char col7[] = "#BFBFBF"; -static const char col8[] = "#4D4D4D"; -static const char col9[] = "#FF6E67"; -static const char col10[] = "#5AF78E"; -static const char col11[] = "#F4F99D"; -static const char col12[] = "#CAA9FA"; -static const char col13[] = "#FF92D0"; -static const char col14[] = "#9AEDFE"; -static const char col15[] = "#E6E6E6"; - -static const char spotify[]= "#1FC167"; - - -static const char *colors[][3] = { - /* fg bg border */ - [SchemeNorm] = { fore, back, back }, // \x0b - [SchemeSel] = { fore, back, border }, // \x0c - [SchemeStatus] = { fore, back, border }, // \x0d Statusbar right - [SchemeTagsSel] = { col4, back, border }, // \x0e Tagbar left selected - [SchemeTagsNorm] = { fore, back, border }, // \x0f Tagbar left unselected - [SchemeInfoSel] = { fore, back, border }, // \x10 infobar middle selected - [SchemeInfoNorm] = { fore, back, border }, // \x11 infobar middle unselected - [SchemeCol1] = { col1, back, col0 }, // \x12 - [SchemeCol2] = { col2, back, col0 }, // \x13 - [SchemeCol3] = { col3, back, col0 }, // \x14 - [SchemeCol4] = { col4, back, col0 }, // \x15 - [SchemeCol5] = { col5, back, col0 }, // \x16 - [SchemeCol6] = { col6, back, col0 }, // \x17 - [SchemeCol7] = { col7, back, col0 }, // \x18 - [SchemeCol8] = { col8, back, col0 }, // \x19 - [SchemeCol9] = { col9, back, col0 }, // \x1a - [SchemeCol10] = { col10, back, col0 }, // \x1b - [SchemeCol11] = { col11, back, col0 }, // \x1c - [SchemeCol12] = { spotify, back, col0 }, // \x1d Spotify -}; +static int showsystray = 1; /* 0 means no systray */ +static const int tag_padding = 0; +static const char *layoutmenu_cmd = "layoutmenu.sh"; + +/* systray */ +static int tagindicatortype = INDICATOR_TOP_LEFT_SQUARE; +static int tiledindicatortype = INDICATOR_NONE; +static int floatindicatortype = INDICATOR_TOP_LEFT_SQUARE; + +/* vanity gaps */ +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 const int smartgaps = 0; /* 1 means no outer gap when there is only one window */ /* tagging */ -static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"}; -//static const char *alttags[] = { "󰄯", "󰄯", "󰄯", "󰄯"}; - -static const Rule rules[] = { - /* xprop(1): - * WM_CLASS(STRING) = instance, class - * WM_NAME(STRING) = title - */ - /* class instance title tags mask isfloating monitor */ - { "discord", NULL, NULL, 1 << 8, 0, -1 }, - { "Mailspring", NULL, NULL, 1 << 7, 0, -1 }, - { "Thunderbird", NULL, NULL, 1 << 7, 0, -1 }, - { "Termite", NULL, NULL, 1 << 0, 0, -1 }, - { "firefoxdeveloperedition", NULL, NULL, 1 << 1, 0, -1 }, - { "Tor Browser", NULL, NULL, 1 << 1, 0, -1 }, - { "Chromium", NULL, NULL, 1 << 1, 0, -1 }, -// { "zoom", NULL, NULL, 1 << 4, 0, -1 }, - { "TelegramDesktop", NULL, NULL, 1 << 8, 0, -1 }, - { "whatsapp-nativefier-d52542", NULL, NULL, 1 << 8, 0, -1 }, - { "neomutt", NULL, NULL, 1 << 7, 0, -1 }, - { "Sublime_Text", NULL, NULL, 1 << 2, 0, -1 }, - { "code-oss", NULL, NULL, 1 << 2, 0, -1 }, - { "jetbrains-idea", NULL, NULL, 1 << 2, 0, -1 }, - { "Nemo", NULL, NULL, 1 << 3, 0, -1 }, - { "Spotify", NULL, NULL, 1 << 9, 0, -1 }, +static char *tagicons[][NUMTAGS] = { + [DEFAULT_TAGS] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }, + [ALTERNATIVE_TAGS] = { "A", "B", "C", "D", "E", "F", "G", "H", "I" }, }; - + /* layout(s) */ static const float mfact = 0.5; /* factor of master area size [0.05..0.95] */ static const int nmaster = 1; /* number of clients in master area */ static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */ -#include "fibonacci.c" -#include "layouts.c" static const Layout layouts[] = { /* symbol arrange function */ { "鉶", tile }, /* first entry is default */ - { "", dwindle }, + { "", dwindle }, { "ﱖ", grid }, { "", centeredmaster }, { "", centeredfloatingmaster }, { "[M]", monocle }, { "[D]", deck }, - { NULL, NULL }, }; -/* key definitions */ -#define MODKEY Mod4Mask -#define TAGKEYS(KEY,TAG) \ - { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ - { MODKEY|Mod1Mask, KEY, toggleview, {.ui = 1 << TAG} }, \ - { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ - { MODKEY|ControlMask, KEY, toggletag, {.ui = 1 << TAG} }, - -/* COSAS QUE TENGO QUE AVERIGUAR COMO QUITAR */ - -/* helper for spawning shell commands in the pre dwm-5.0 fashion */ -#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } -static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ -static const char *dmenucmd[] = { "/usr/bin/rofi","-show","drun", NULL }; -static const char *termcmd[] = { "/usr/bin/termite", "--title", "Terminal", NULL }; -static const char *upvol[] = { "/usr/bin/pactl", "set-sink-volume", "0", "+5%", NULL }; -static const char *downvol[] = { "/usr/bin/pactl", "set-sink-volume", "0", "-5%", NULL }; -static const char *mutevol[] = { "/usr/bin/pactl", "set-sink-mute", "0", "toggle", NULL }; - -static const char *upbright[] = {"/usr/bin/xbacklight","-inc","10",NULL}; -static const char *downbright[] = {"/usr/bin/xbacklight","-dec","10",NULL}; - -static const char *lock[] = {"/usr/bin/betterlockscreen","-l","-t","Stay the fuck out!",NULL}; -static const char *clipmenu[] = {"/usr/bin/clipmenu","-i",NULL}; -static const char *play[] = {"/usr/bin/playerctl","play-pause",NULL}; -static const char *prev[] = {"/usr/bin/playerctl","previous",NULL}; -static const char *next[] = {"/usr/bin/playerctl","next",NULL}; -static const char *outmenu[] = {"/home/yigit/.scripts/dmenu-logout"}; - -static const char *notification_off[] = {"/home/yigit/.scripts/dunst_toggle.sh","-s",NULL}; -static const char *notification_on[] = {"/home/yigit/.scripts/dunst_toggle.sh", "-e",NULL}; - -static const char *bwmenu[] = {"/usr/bin/bwmenu", "--auto-lock", "-1", NULL}; - -static const char *trackpad[] = {"/home/yigit/.scripts/toggle_touchpad.sh"}; - -static const char *kdeconnect[] = {"/home/yigit/.local/bin/dmenu_kdeconnect.sh", NULL}; - -static const char *bluetooth[] = {"/usr/bin/rofi-bluetooth", NULL}; - -static const char *screenshot[] = { "scrot","-d","3", "%Y-%m-%d-%s_$wx$h.jpg", "-e","xclip -selection clipboard -t image/jpg < $f; mv $f ~/Pictures/Screenshots/;dunstify --icon='/home/yigit/.icons/Numix-Circle/48/apps/camera.svg' -a 'SNAP' 'Screenshot taken'", NULL }; -static const char *windowshot[] = { "scrot", "-u", "-d","3", "%Y-%m-%d-%s_$wx$h.jpg", "-e","xclip -selection clipboard -t image/jpg < $f; mv $f ~/Pictures/Screenshots/;dunstify --icon='/home/yigit/.icons/Numix-Circle/48/apps/camera.svg' -a 'SNAP' 'Screenshot taken'", NULL }; - -/* commands */ -#include "movestack.c" -#include "shiftview.c" -static Key keys[] = { - /* modifier key function argument */ - { MODKEY, XK_d, spawn, {.v = dmenucmd } }, - { MODKEY, XK_p, spawn, {.v = bwmenu } }, - { MODKEY, XK_Return, spawn, {.v = termcmd } }, - { MODKEY, XK_b, togglebar, {0} }, - { MODKEY, XK_j, focusstack, {.i = +1 } }, - { MODKEY, XK_n, spawn, {.v = notification_off} }, - { MODKEY|ShiftMask, XK_n, spawn, {.v = notification_on } }, - { MODKEY, XK_k, focusstack, {.i = -1 } }, - { MODKEY, XK_i, incnmaster, {.i = +1 } }, - { MODKEY, XK_s, incnmaster, {.i = -1 } }, - { MODKEY, XK_h, setmfact, {.f = -0.05} }, - { MODKEY, XK_l, setmfact, {.f = +0.05} }, - { MODKEY|ShiftMask, XK_Return, zoom, {0} }, - { MODKEY, XK_Tab, view, {0} }, - { MODKEY, XK_q, killclient, {0} }, - { MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } }, /*Mover ventana hacia abajo*/ - { MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } }, /*Mover ventana hacia arriba*/ - { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, /*tiled*/ - { MODKEY|Mod1Mask, XK_f, setlayout, {.v = &layouts[1]} }, /*Spiral*/ - { MODKEY|Mod1Mask, XK_g, setlayout, {.v = &layouts[2]} }, /*Grid*/ - { MODKEY|Mod1Mask, XK_c, setlayout, {.v = &layouts[3]} }, /*center*/ - { MODKEY, XK_m, setlayout, {.v = &layouts[5]} }, /*monocle*/ - { MODKEY|ShiftMask, XK_m, setlayout, {.v = &layouts[6]} }, /*Deck*/ - { MODKEY, XK_s, togglefloating, {0} }, /*float*/ - { MODKEY, XK_f, togglefullscr, {0} }, /*Fullscreen*/ - { MODKEY|Mod1Mask, XK_comma, cyclelayout, {.i = -1 } }, /*Ciclar layouts*/ - { MODKEY|Mod1Mask, XK_period, cyclelayout, {.i = +1 } }, /*Ciclar layouts*/ - { MODKEY, XK_a, view, {.ui = ~0 } }, - { MODKEY|ShiftMask, XK_a, 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 } }, - /*Monitores*/ - { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, /*Mandar ventana a monitor anterior*/ - { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, /*Mandar ventana a monitor siguiente*/ - 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) - TAGKEYS( XK_0, 9) - { MODKEY|ShiftMask, XK_q, spawn, {.v = outmenu} }, - { MODKEY|ShiftMask, XK_t, spawn, {.v = trackpad} }, - { MODKEY, XK_x, spawn, {.v = lock } }, - { MODKEY, XK_c, spawn, {.v = clipmenu } }, - { MODKEY|ShiftMask, XK_p, spawn, {.v = kdeconnect } }, - { MODKEY|ShiftMask, XK_b, spawn, {.v = bluetooth } }, - { 0, XF86XK_AudioLowerVolume, spawn, {.v = downvol } }, - { 0, XF86XK_MonBrightnessUp, spawn, {.v = upbright } }, - { 0, XF86XK_MonBrightnessDown, spawn, {.v = downbright } }, - { 0, XF86XK_AudioMute, spawn, {.v = mutevol } }, - { 0, XF86XK_AudioRaiseVolume, spawn, {.v = upvol } }, - { 0, XF86XK_AudioPrev, spawn, {.v = prev } }, - { 0, XF86XK_AudioPlay, spawn, {.v = play } }, - { 0, XF86XK_AudioNext, spawn, {.v = next } }, - { 0, XK_Print, spawn, {.v = screenshot } }, - { MODKEY, XK_Print, spawn, {.v = windowshot } }, - -}; - -/* button definitions */ -/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ - -static Button buttons[] = { - /* click event mask button function argument */ - { ClkLtSymbol, 0, Button1, setlayout, {0} }, - { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, - { 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} }, -}; -/* -static Button buttons[] = { - // click event mask button function argument - { ClkLtSymbol, 0, Button1, cyclelayout, {.i = +1 } }, - { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[5]} }, - { ClkWinTitle, 0, Button2, zoom, {0} }, - { ClkStatusText, 0, Button1, sigdwmblocks, {.i = 1} }, - { ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2} }, - { ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3} }, - { 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} }, - { ClkClientWin, 0, Button1, winview, {0} }, +static const BarRule barrules[] = { + /* monitor bar alignment widthfunc drawfunc clickfunc name */ + { -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, "tags" }, + //{ 0, 0, BAR_ALIGN_RIGHT, width_systray, draw_systray, click_systray, "systray" }, + { -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, "layout" }, + { 'A', 0, BAR_ALIGN_RIGHT, width_status2d, draw_status2d, click_statuscmd, "status2d" }, }; -*/ diff --git a/suckless/dwm/config.mk b/suckless/dwm/config.mk index 7084c333..2f2b6958 100644 --- a/suckless/dwm/config.mk +++ b/suckless/dwm/config.mk @@ -19,10 +19,32 @@ FREETYPELIBS = -lfontconfig -lXft FREETYPEINC = /usr/include/freetype2 # OpenBSD (uncomment) #FREETYPEINC = ${X11INC}/freetype2 +# OpenBSD - Uncomment this for the swallow patch / SWALLOW_PATCH +#KVMLIB = -lkvm + +# Uncomment this for the alpha patch / BAR_ALPHA_PATCH +XRENDER = -lXrender + +# Uncomment this for the mdpcontrol patch / MDPCONTROL_PATCH +#MPDCLIENT = -lmpdclient + +# Uncomment for the pango patch / BAR_PANGO_PATCH +#PANGOINC = `pkg-config --cflags xft pango pangoxft` +#PANGOLIB = `pkg-config --libs xft pango pangoxft` + +# Uncomment for the ipc patch / IPC_PATCH +YAJLLIBS = -lyajl +YAJLINC = -I/usr/include/yajl + +# Uncomment this for the rounded corners patch / ROUNDED_CORNERS_PATCH +#XEXTLIB = -lXext + +# Uncomment this for the swallow patch / SWALLOW_PATCH +XCBLIBS = -lX11-xcb -lxcb -lxcb-res # includes and libs -INCS = -I${X11INC} -I${FREETYPEINC} -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} +INCS = -I${X11INC} -I${FREETYPEINC} ${YAJLINC} ${PANGOINC} +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${XRENDER} ${MPDCLIENT} ${XEXTLIB} ${XCBLIBS} ${KVMLIB} ${PANGOLIB} ${YAJLLIBS} # flags CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} diff --git a/suckless/dwm/drw.c b/suckless/dwm/drw.c index cd899f89..da9101ae 100644 --- a/suckless/dwm/drw.c +++ b/suckless/dwm/drw.c @@ -5,9 +5,11 @@ #include #include +#include "patches.h" #include "drw.h" #include "util.h" +#if !BAR_PANGO_PATCH #define UTF_INVALID 0xFFFD #define UTF_SIZ 4 @@ -15,7 +17,13 @@ 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}; +#endif // BAR_PANGO_PATCH +#if BAR_POWERLINE_TAGS_PATCH || BAR_POWERLINE_STATUS_PATCH +Clr transcheme[3]; +#endif // BAR_POWERLINE_TAGS_PATCH | BAR_POWERLINE_STATUS_PATCH + +#if !BAR_PANGO_PATCH static long utf8decodebyte(const char c, size_t *i) { @@ -59,9 +67,14 @@ utf8decode(const char *c, long *u, size_t clen) return len; } +#endif // BAR_PANGO_PATCH Drw * +#if BAR_ALPHA_PATCH +drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap) +#else drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h) +#endif // BAR_ALPHA_PATCH { Drw *drw = ecalloc(1, sizeof(Drw)); @@ -70,8 +83,17 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h drw->root = root; drw->w = w; drw->h = h; + + #if BAR_ALPHA_PATCH + 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); + #else drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); drw->gc = XCreateGC(dpy, root, 0, NULL); + #endif // BAR_ALPHA_PATCH XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); return drw; @@ -87,7 +109,11 @@ drw_resize(Drw *drw, unsigned int w, unsigned int h) drw->h = h; if (drw->drawable) XFreePixmap(drw->dpy, drw->drawable); + #if BAR_ALPHA_PATCH + drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, drw->depth); + #else drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen)); + #endif // BAR_ALPHA_PATCH } void @@ -99,6 +125,41 @@ drw_free(Drw *drw) free(drw); } +#if BAR_PANGO_PATCH +/* This function is an implementation detail. Library users should use + * drw_font_create instead. + */ +static Fnt * +xfont_create(Drw *drw, const char *fontname) +{ + Fnt *font; + PangoFontMap *fontmap; + PangoContext *context; + PangoFontDescription *desc; + PangoFontMetrics *metrics; + + if (!fontname) { + die("no font specified."); + } + + font = ecalloc(1, sizeof(Fnt)); + font->dpy = drw->dpy; + + fontmap = pango_xft_get_font_map(drw->dpy, drw->screen); + context = pango_font_map_create_context(fontmap); + desc = pango_font_description_from_string(fontname); + font->layout = pango_layout_new(context); + pango_layout_set_font_description(font->layout, desc); + + metrics = pango_context_get_metrics(context, desc, pango_language_from_string ("en-us")); + font->h = pango_font_metrics_get_height(metrics) / PANGO_SCALE; + + pango_font_metrics_unref(metrics); + g_object_unref(context); + + return font; +} +#else /* This function is an implementation detail. Library users should use * drw_fontset_create instead. */ @@ -133,6 +194,7 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) die("no font specified."); } + #if !BAR_COLOR_EMOJI_PATCH /* Do not allow using color fonts. This is a workaround for a BadLength * error from Xft with color glyphs. Modelled on the Xterm workaround. See * https://bugzilla.redhat.com/show_bug.cgi?id=1498269 @@ -141,10 +203,11 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) * and lots more all over the internet. */ FcBool iscol; - if(FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) { + if (FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) { XftFontClose(drw->dpy, xfont); return NULL; } + #endif // BAR_COLOR_EMOJI_PATCH font = ecalloc(1, sizeof(Fnt)); font->xfont = xfont; @@ -154,18 +217,38 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) return font; } +#endif // BAR_PANGO_PATCH static void xfont_free(Fnt *font) { if (!font) return; + #if BAR_PANGO_PATCH + if (font->layout) + g_object_unref(font->layout); + #else if (font->pattern) FcPatternDestroy(font->pattern); XftFontClose(font->dpy, font->xfont); + #endif // BAR_PANGO_PATCH free(font); } +#if BAR_PANGO_PATCH +Fnt* +drw_font_create(Drw* drw, const char font[]) +{ + Fnt *fnt = NULL; + + if (!drw || !font) + return NULL; + + fnt = xfont_create(drw, font); + + return (drw->fonts = fnt); +} +#else Fnt* drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount) { @@ -183,35 +266,60 @@ drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount) } return (drw->fonts = ret); } +#endif // BAR_PANGO_PATCH void drw_fontset_free(Fnt *font) { if (font) { + #if !BAR_PANGO_PATCH drw_fontset_free(font->next); + #endif // BAR_PANGO_PATCH xfont_free(font); } } void -drw_clr_create(Drw *drw, Clr *dest, const char *clrname) -{ +drw_clr_create( + Drw *drw, + Clr *dest, + const char *clrname + #if BAR_ALPHA_PATCH + , unsigned int alpha + #endif // BAR_ALPHA_PATCH +) { if (!drw || !dest || !clrname) return; + #if BAR_ALPHA_PATCH + if (!XftColorAllocName(drw->dpy, drw->visual, drw->cmap, + clrname, dest)) + die("error, cannot allocate color '%s'", clrname); + + dest->pixel = (dest->pixel & 0x00ffffffU) | (alpha << 24); + #else if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen), DefaultColormap(drw->dpy, drw->screen), clrname, dest)) die("error, cannot allocate color '%s'", clrname); + #if NO_TRANSPARENT_BORDERS_PATCH dest->pixel |= 0xff << 24; + #endif // NO_TRANSPARENT_BORDERS_PATCH + #endif // BAR_ALPHA_PATCH } /* 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[], + #if BAR_ALPHA_PATCH + const unsigned int alphas[], + #endif // BAR_ALPHA_PATCH + size_t clrcount +) { size_t i; Clr *ret; @@ -220,16 +328,22 @@ drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) return NULL; for (i = 0; i < clrcount; i++) + #if BAR_ALPHA_PATCH + drw_clr_create(drw, &ret[i], clrnames[i], alphas[i]); + #else drw_clr_create(drw, &ret[i], clrnames[i]); + #endif // BAR_ALPHA_PATCH return ret; } +#if !BAR_PANGO_PATCH void drw_setfontset(Drw *drw, Fnt *set) { if (drw) drw->fonts = set; } +#endif // BAR_PANGO_PATCH void drw_setscheme(Drw *drw, Clr *scm) @@ -238,6 +352,17 @@ drw_setscheme(Drw *drw, Clr *scm) drw->scheme = scm; } +#if BAR_POWERLINE_TAGS_PATCH || BAR_POWERLINE_STATUS_PATCH +void +drw_settrans(Drw *drw, Clr *psc, Clr *nsc) +{ + if (drw) { + transcheme[0] = psc[ColBg]; transcheme[1] = nsc[ColBg]; transcheme[2] = psc[ColBorder]; + drw->scheme = transcheme; + } +} +#endif // BAR_POWERLINE_TAGS_PATCH | BAR_POWERLINE_STATUS_PATCH + void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert) { @@ -250,8 +375,74 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1); } +#if BAR_PANGO_PATCH +int +drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool markup) +{ + char buf[1024]; + int ty; + unsigned int ew; + XftDraw *d = NULL; + size_t i, len; + int render = x || y || w || h; + + if (!drw || (render && !drw->scheme) || !text || !drw->fonts) + return 0; + + if (!render) { + w = ~w; + } else { + XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); + #if BAR_ALPHA_PATCH + d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap); + #else + d = XftDrawCreate(drw->dpy, drw->drawable, + DefaultVisual(drw->dpy, drw->screen), + DefaultColormap(drw->dpy, drw->screen)); + #endif // BAR_ALPHA_PATCH + x += lpad; + w -= lpad; + } + + len = strlen(text); + + if (len) { + drw_font_getexts(drw->fonts, text, len, &ew, NULL, markup); + /* shorten text if necessary */ + for (len = MIN(len, sizeof(buf) - 1); len && ew > w; len--) + drw_font_getexts(drw->fonts, text, len, &ew, NULL, markup); + + if (len) { + memcpy(buf, text, len); + buf[len] = '\0'; + if (len < strlen(text)) + for (i = len; i && i > len - 3; buf[--i] = '.') + ; /* NOP */ + + if (render) { + ty = y + (h - drw->fonts->h) / 2; + if (markup) + pango_layout_set_markup(drw->fonts->layout, buf, len); + else + pango_layout_set_text(drw->fonts->layout, buf, len); + pango_xft_render_layout(d, &drw->scheme[invert ? ColBg : ColFg], + drw->fonts->layout, x * PANGO_SCALE, ty * PANGO_SCALE); + if (markup) /* clear markup attributes */ + pango_layout_set_attributes(drw->fonts->layout, NULL); + } + x += ew; + w -= ew; + } + } + if (d) + XftDrawDestroy(d); + + return x + (render ? w : 0); +} +#else int -drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert) +drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool ignored) { char buf[1024]; int ty; @@ -276,9 +467,13 @@ 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); + #if BAR_ALPHA_PATCH + d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap); + #else d = XftDrawCreate(drw->dpy, drw->drawable, DefaultVisual(drw->dpy, drw->screen), DefaultColormap(drw->dpy, drw->screen)); + #endif // BAR_ALPHA_PATCH x += lpad; w -= lpad; } @@ -380,6 +575,40 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp return x + (render ? w : 0); } +#endif // BAR_PANGO_PATCH + +#if BAR_POWERLINE_TAGS_PATCH || BAR_POWERLINE_STATUS_PATCH +void +drw_arrow(Drw *drw, int x, int y, unsigned int w, unsigned int h, int direction, int slash) +{ + if (!drw || !drw->scheme) + return; + + /* direction=1 draws right arrow */ + x = direction ? x : x + w; + w = direction ? w : -w; + /* slash=1 draws slash instead of arrow */ + unsigned int hh = slash ? (direction ? 0 : h) : h/2; + + XPoint points[] = { + {x , y }, + {x + w, y + hh }, + {x , y + h }, + }; + + XPoint bg[] = { + {x , y }, + {x + w, y }, + {x + w, y + h}, + {x , y + h}, + }; + + XSetForeground(drw->dpy, drw->gc, drw->scheme[ColBg].pixel); + XFillPolygon(drw->dpy, drw->drawable, drw->gc, bg, 4, Convex, CoordModeOrigin); + XSetForeground(drw->dpy, drw->gc, drw->scheme[ColFg].pixel); + XFillPolygon(drw->dpy, drw->drawable, drw->gc, points, 3, Nonconvex, CoordModeOrigin); +} +#endif // BAR_POWERLINE_TAGS_PATCH | BAR_POWERLINE_STATUS_PATCH void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) @@ -392,13 +621,34 @@ drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) } unsigned int -drw_fontset_getwidth(Drw *drw, const char *text) +drw_fontset_getwidth(Drw *drw, const char *text, Bool markup) { if (!drw || !drw->fonts || !text) return 0; - return drw_text(drw, 0, 0, 0, 0, 0, text, 0); + return drw_text(drw, 0, 0, 0, 0, 0, text, 0, markup); } +#if BAR_PANGO_PATCH +void +drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h, Bool markup) +{ + if (!font || !text) + return; + + PangoRectangle r; + if (markup) + pango_layout_set_markup(font->layout, text, len); + else + pango_layout_set_text(font->layout, text, len); + pango_layout_get_extents(font->layout, 0, &r); + if (markup) /* clear markup attributes */ + pango_layout_set_attributes(font->layout, NULL); + if (w) + *w = r.width / PANGO_SCALE; + if (h) + *h = font->h; +} +#else void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h) { @@ -413,6 +663,7 @@ drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, if (h) *h = font->h; } +#endif // BAR_PANGO_PATCH Cur * drw_cur_create(Drw *drw, int shape) diff --git a/suckless/dwm/drw.h b/suckless/dwm/drw.h index 4bcd5add..f4eac030 100644 --- a/suckless/dwm/drw.h +++ b/suckless/dwm/drw.h @@ -1,5 +1,10 @@ /* See LICENSE file for copyright and license details. */ +#if BAR_PANGO_PATCH +#include +#include +#endif // BAR_PANGO_PATCH + typedef struct { Cursor cursor; } Cur; @@ -7,12 +12,16 @@ typedef struct { typedef struct Fnt { Display *dpy; unsigned int h; + #if BAR_PANGO_PATCH + PangoLayout *layout; + #else XftFont *xfont; FcPattern *pattern; struct Fnt *next; + #endif // BAR_PANGO_PATCH } Fnt; -enum { ColFg, ColBg, ColBorder }; /* Clr scheme index */ +enum { ColFg, ColBg, ColBorder, ColFloat, ColCount }; /* Clr scheme index */ typedef XftColor Clr; typedef struct { @@ -20,6 +29,11 @@ typedef struct { Display *dpy; int screen; Window root; + #if BAR_ALPHA_PATCH + Visual *visual; + unsigned int depth; + Colormap cmap; + #endif // BAR_ALPHA_PATCH Drawable drawable; GC gc; Clr *scheme; @@ -27,31 +41,62 @@ typedef struct { } Drw; /* Drawable abstraction */ +#if BAR_ALPHA_PATCH +Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap); +#else Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h); +#endif // BAR_ALPHA_PATCH void drw_resize(Drw *drw, unsigned int w, unsigned int h); void drw_free(Drw *drw); /* Fnt abstraction */ +#if BAR_PANGO_PATCH +Fnt *drw_font_create(Drw* drw, const char font[]); +void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h, Bool markup); +#else Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount); -void drw_fontset_free(Fnt* set); -unsigned int drw_fontset_getwidth(Drw *drw, const char *text); void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h); +#endif // BAR_PANGO_PATCH +void drw_fontset_free(Fnt* set); +unsigned int drw_fontset_getwidth(Drw *drw, const char *text, Bool markup); /* 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 + #if BAR_ALPHA_PATCH + , unsigned int alpha + #endif // BAR_ALPHA_PATCH +); +Clr *drw_scm_create( + Drw *drw, + char *clrnames[], + #if BAR_ALPHA_PATCH + const unsigned int alphas[], + #endif // BAR_ALPHA_PATCH + size_t clrcount +); /* Cursor abstraction */ Cur *drw_cur_create(Drw *drw, int shape); void drw_cur_free(Drw *drw, Cur *cursor); /* Drawing context manipulation */ +#if !BAR_PANGO_PATCH void drw_setfontset(Drw *drw, Fnt *set); +#endif // BAR_PANGO_PATCH void drw_setscheme(Drw *drw, Clr *scm); +#if BAR_POWERLINE_TAGS_PATCH || BAR_POWERLINE_STATUS_PATCH +void drw_settrans(Drw *drw, Clr *psc, Clr *nsc); +#endif // BAR_POWERLINE_TAGS_PATCH | BAR_POWERLINE_STATUS_PATCH /* 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); +int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool markup); +#if BAR_POWERLINE_TAGS_PATCH || BAR_POWERLINE_STATUS_PATCH +void drw_arrow(Drw *drw, int x, int y, unsigned int w, unsigned int h, int direction, int slash); +#endif // BAR_POWERLINE_TAGS_PATCH | BAR_POWERLINE_STATUS_PATCH /* Map functions */ void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); diff --git a/suckless/dwm/dwm-systray-20200914-61bb8b2.diff b/suckless/dwm/dwm-systray-20200914-61bb8b2.diff deleted file mode 100644 index b2a4d572..00000000 --- a/suckless/dwm/dwm-systray-20200914-61bb8b2.diff +++ /dev/null @@ -1,727 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index 1c0b587..2d824d1 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -3,6 +3,10 @@ - /* appearance */ - static const unsigned int borderpx = 1; /* border pixel of windows */ - static const unsigned int snap = 32; /* snap pixel */ -+static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ -+static const unsigned int systrayspacing = 2; /* systray spacing */ -+static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ -+static const int showsystray = 1; /* 0 means no systray */ - 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" }; -diff --git a/dwm.c b/dwm.c -index 664c527..abce13d 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -57,12 +57,30 @@ - #define TAGMASK ((1 << LENGTH(tags)) - 1) - #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) - -+#define SYSTEM_TRAY_REQUEST_DOCK 0 -+ -+/* XEMBED messages */ -+#define XEMBED_EMBEDDED_NOTIFY 0 -+#define XEMBED_WINDOW_ACTIVATE 1 -+#define XEMBED_FOCUS_IN 4 -+#define XEMBED_MODALITY_ON 10 -+ -+#define XEMBED_MAPPED (1 << 0) -+#define XEMBED_WINDOW_ACTIVATE 1 -+#define XEMBED_WINDOW_DEACTIVATE 2 -+ -+#define VERSION_MAJOR 0 -+#define VERSION_MINOR 0 -+#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR -+ - /* enums */ - enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ - enum { SchemeNorm, SchemeSel }; /* color schemes */ - enum { NetSupported, NetWMName, NetWMState, NetWMCheck, -+ NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz, - NetWMFullscreen, NetActiveWindow, NetWMWindowType, - NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ -+enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ - enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ - enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, - ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ -@@ -141,6 +159,12 @@ typedef struct { - int monitor; - } Rule; - -+typedef struct Systray Systray; -+struct Systray { -+ Window win; -+ Client *icons; -+}; -+ - /* function declarations */ - static void applyrules(Client *c); - static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); -@@ -172,6 +196,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 unsigned int getsystraywidth(); - static int gettextprop(Window w, Atom atom, char *text, unsigned int size); - static void grabbuttons(Client *c, int focused); - static void grabkeys(void); -@@ -189,13 +214,16 @@ 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 removesystrayicon(Client *i); - static void resize(Client *c, int x, int y, int w, int h, int interact); -+static void resizebarwin(Monitor *m); - static void resizeclient(Client *c, int x, int y, int w, int h); - static void resizemouse(const Arg *arg); -+static void resizerequest(XEvent *e); - static void restack(Monitor *m); - static void run(void); - static void scan(void); --static int sendevent(Client *c, Atom proto); -+static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); - static void sendmon(Client *c, Monitor *m); - static void setclientstate(Client *c, long state); - static void setfocus(Client *c); -@@ -207,6 +235,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 Monitor *systraytomon(Monitor *m); - static void tag(const Arg *arg); - static void tagmon(const Arg *arg); - static void tile(Monitor *); -@@ -224,18 +253,23 @@ static int updategeom(void); - static void updatenumlockmask(void); - static void updatesizehints(Client *c); - static void updatestatus(void); -+static void updatesystray(void); -+static void updatesystrayicongeom(Client *i, int w, int h); -+static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); - static void updatetitle(Client *c); - static void updatewindowtype(Client *c); - static void updatewmhints(Client *c); - static void view(const Arg *arg); - static Client *wintoclient(Window w); - static Monitor *wintomon(Window w); -+static Client *wintosystrayicon(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 Systray *systray = NULL; - static const char broken[] = "broken"; - static char stext[256]; - static int screen; -@@ -258,9 +292,10 @@ static void (*handler[LASTEvent]) (XEvent *) = { - [MapRequest] = maprequest, - [MotionNotify] = motionnotify, - [PropertyNotify] = propertynotify, -+ [ResizeRequest] = resizerequest, - [UnmapNotify] = unmapnotify - }; --static Atom wmatom[WMLast], netatom[NetLast]; -+static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; - static int running = 1; - static Cur *cursor[CurLast]; - static Clr **scheme; -@@ -440,7 +475,7 @@ buttonpress(XEvent *e) - arg.ui = 1 << i; - } else if (ev->x < x + blw) - click = ClkLtSymbol; -- else if (ev->x > selmon->ww - (int)TEXTW(stext)) -+ else if (ev->x > selmon->ww - (int)TEXTW(stext) - getsystraywidth()) - click = ClkStatusText; - else - click = ClkWinTitle; -@@ -483,6 +518,11 @@ cleanup(void) - XUngrabKey(dpy, AnyKey, AnyModifier, root); - while (mons) - cleanupmon(mons); -+ if (showsystray) { -+ XUnmapWindow(dpy, systray->win); -+ XDestroyWindow(dpy, systray->win); -+ free(systray); -+ } - for (i = 0; i < CurLast; i++) - drw_cur_free(drw, cursor[i]); - for (i = 0; i < LENGTH(colors); i++) -@@ -513,9 +553,57 @@ cleanupmon(Monitor *mon) - void - clientmessage(XEvent *e) - { -+ XWindowAttributes wa; -+ XSetWindowAttributes swa; - XClientMessageEvent *cme = &e->xclient; - Client *c = wintoclient(cme->window); - -+ if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { -+ /* add systray icons */ -+ if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { -+ if (!(c = (Client *)calloc(1, sizeof(Client)))) -+ die("fatal: could not malloc() %u bytes\n", sizeof(Client)); -+ if (!(c->win = cme->data.l[2])) { -+ free(c); -+ return; -+ } -+ c->mon = selmon; -+ c->next = systray->icons; -+ systray->icons = c; -+ if (!XGetWindowAttributes(dpy, c->win, &wa)) { -+ /* use sane defaults */ -+ wa.width = bh; -+ wa.height = bh; -+ wa.border_width = 0; -+ } -+ c->x = c->oldx = c->y = c->oldy = 0; -+ c->w = c->oldw = wa.width; -+ c->h = c->oldh = wa.height; -+ c->oldbw = wa.border_width; -+ c->bw = 0; -+ c->isfloating = True; -+ /* reuse tags field as mapped status */ -+ c->tags = 1; -+ updatesizehints(c); -+ updatesystrayicongeom(c, wa.width, wa.height); -+ XAddToSaveSet(dpy, c->win); -+ XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); -+ XReparentWindow(dpy, c->win, systray->win, 0, 0); -+ /* use parents background color */ -+ swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; -+ XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); -+ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION); -+ /* FIXME not sure if I have to send these events, too */ -+ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION); -+ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION); -+ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION); -+ XSync(dpy, False); -+ resizebarwin(selmon); -+ updatesystray(); -+ setclientstate(c, NormalState); -+ } -+ return; -+ } - if (!c) - return; - if (cme->message_type == netatom[NetWMState]) { -@@ -568,7 +656,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); -+ resizebarwin(m); - } - focus(NULL); - arrange(NULL); -@@ -653,6 +741,11 @@ destroynotify(XEvent *e) - - if ((c = wintoclient(ev->window))) - unmanage(c, 1); -+ else if ((c = wintosystrayicon(ev->window))) { -+ removesystrayicon(c); -+ resizebarwin(selmon); -+ updatesystray(); -+ } - } - - void -@@ -696,19 +789,23 @@ dirtomon(int dir) - void - drawbar(Monitor *m) - { -- int x, w, tw = 0; -+ int x, w, tw = 0, stw = 0; - int boxs = drw->fonts->h / 9; - int boxw = drw->fonts->h / 6 + 2; - unsigned int i, occ = 0, urg = 0; - Client *c; - -+ if(showsystray && m == systraytomon(m)) -+ stw = getsystraywidth(); -+ - /* 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]); -- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ -- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); -+ tw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ -+ drw_text(drw, m->ww - tw - stw, 0, tw, bh, lrpad / 2 - 2, stext, 0); - } - -+ resizebarwin(m); - for (c = m->clients; c; c = c->next) { - occ |= c->tags; - if (c->isurgent) -@@ -729,7 +826,7 @@ drawbar(Monitor *m) - 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 ((w = m->ww - tw - stw - 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); -@@ -740,7 +837,7 @@ drawbar(Monitor *m) - drw_rect(drw, x, 0, w, bh, 1, 1); - } - } -- drw_map(drw, m->barwin, 0, 0, m->ww, bh); -+ drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh); - } - - void -@@ -777,8 +874,11 @@ expose(XEvent *e) - Monitor *m; - XExposeEvent *ev = &e->xexpose; - -- if (ev->count == 0 && (m = wintomon(ev->window))) -+ if (ev->count == 0 && (m = wintomon(ev->window))) { - drawbar(m); -+ if (m == selmon) -+ updatesystray(); -+ } - } - - void -@@ -863,10 +963,17 @@ getatomprop(Client *c, Atom prop) - unsigned long dl; - unsigned char *p = NULL; - Atom da, atom = None; -+ /* FIXME getatomprop should return the number of items and a pointer to -+ * the stored data instead of this workaround */ -+ Atom req = XA_ATOM; -+ if (prop == xatom[XembedInfo]) -+ req = xatom[XembedInfo]; - -- if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, -+ if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, - &da, &di, &dl, &dl, &p) == Success && p) { - atom = *(Atom *)p; -+ if (da == xatom[XembedInfo] && dl == 2) -+ atom = ((Atom *)p)[1]; - XFree(p); - } - return atom; -@@ -900,6 +1007,16 @@ getstate(Window w) - return result; - } - -+unsigned int -+getsystraywidth() -+{ -+ unsigned int w = 0; -+ Client *i; -+ if(showsystray) -+ for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ; -+ return w ? w + systrayspacing : 1; -+} -+ - int - gettextprop(Window w, Atom atom, char *text, unsigned int size) - { -@@ -1004,7 +1121,7 @@ killclient(const Arg *arg) - { - if (!selmon->sel) - return; -- if (!sendevent(selmon->sel, wmatom[WMDelete])) { -+ if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { - XGrabServer(dpy); - XSetErrorHandler(xerrordummy); - XSetCloseDownMode(dpy, DestroyAll); -@@ -1092,6 +1209,12 @@ maprequest(XEvent *e) - { - static XWindowAttributes wa; - XMapRequestEvent *ev = &e->xmaprequest; -+ Client *i; -+ if ((i = wintosystrayicon(ev->window))) { -+ sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); -+ resizebarwin(selmon); -+ updatesystray(); -+ } - - if (!XGetWindowAttributes(dpy, ev->window, &wa)) - return; -@@ -1216,6 +1339,16 @@ propertynotify(XEvent *e) - Window trans; - XPropertyEvent *ev = &e->xproperty; - -+ if ((c = wintosystrayicon(ev->window))) { -+ if (ev->atom == XA_WM_NORMAL_HINTS) { -+ updatesizehints(c); -+ updatesystrayicongeom(c, c->w, c->h); -+ } -+ else -+ updatesystrayiconstate(c, ev); -+ resizebarwin(selmon); -+ updatesystray(); -+ } - if ((ev->window == root) && (ev->atom == XA_WM_NAME)) - updatestatus(); - else if (ev->state == PropertyDelete) -@@ -1266,6 +1399,20 @@ recttomon(int x, int y, int w, int h) - return r; - } - -+void -+removesystrayicon(Client *i) -+{ -+ Client **ii; -+ -+ if (!showsystray || !i) -+ return; -+ for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); -+ if (ii) -+ *ii = i->next; -+ free(i); -+} -+ -+ - void - resize(Client *c, int x, int y, int w, int h, int interact) - { -@@ -1273,6 +1420,14 @@ resize(Client *c, int x, int y, int w, int h, int interact) - resizeclient(c, x, y, w, h); - } - -+void -+resizebarwin(Monitor *m) { -+ unsigned int w = m->ww; -+ if (showsystray && m == systraytomon(m)) -+ w -= getsystraywidth(); -+ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); -+} -+ - void - resizeclient(Client *c, int x, int y, int w, int h) - { -@@ -1345,6 +1500,19 @@ resizemouse(const Arg *arg) - } - } - -+void -+resizerequest(XEvent *e) -+{ -+ XResizeRequestEvent *ev = &e->xresizerequest; -+ Client *i; -+ -+ if ((i = wintosystrayicon(ev->window))) { -+ updatesystrayicongeom(i, ev->width, ev->height); -+ resizebarwin(selmon); -+ updatesystray(); -+ } -+} -+ - void - restack(Monitor *m) - { -@@ -1434,26 +1602,36 @@ setclientstate(Client *c, long state) - } - - int --sendevent(Client *c, Atom proto) -+sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) - { - int n; -- Atom *protocols; -+ Atom *protocols, mt; - int exists = 0; - XEvent ev; - -- if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { -- while (!exists && n--) -- exists = protocols[n] == proto; -- XFree(protocols); -+ if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { -+ mt = wmatom[WMProtocols]; -+ if (XGetWMProtocols(dpy, w, &protocols, &n)) { -+ while (!exists && n--) -+ exists = protocols[n] == proto; -+ XFree(protocols); -+ } -+ } -+ else { -+ exists = True; -+ mt = proto; - } - if (exists) { - ev.type = ClientMessage; -- ev.xclient.window = c->win; -- ev.xclient.message_type = wmatom[WMProtocols]; -+ ev.xclient.window = w; -+ ev.xclient.message_type = mt; - ev.xclient.format = 32; -- ev.xclient.data.l[0] = proto; -- ev.xclient.data.l[1] = CurrentTime; -- XSendEvent(dpy, c->win, False, NoEventMask, &ev); -+ ev.xclient.data.l[0] = d0; -+ ev.xclient.data.l[1] = d1; -+ ev.xclient.data.l[2] = d2; -+ ev.xclient.data.l[3] = d3; -+ ev.xclient.data.l[4] = d4; -+ XSendEvent(dpy, w, False, mask, &ev); - } - return exists; - } -@@ -1467,7 +1645,7 @@ setfocus(Client *c) - XA_WINDOW, 32, PropModeReplace, - (unsigned char *) &(c->win), 1); - } -- sendevent(c, wmatom[WMTakeFocus]); -+ sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); - } - - void -@@ -1556,6 +1734,10 @@ setup(void) - wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); - netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); - netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); -+ netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False); -+ netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); -+ netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); -+ netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", 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); -@@ -1563,6 +1745,9 @@ 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); -+ xatom[Manager] = XInternAtom(dpy, "MANAGER", False); -+ xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); -+ xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); - /* init cursors */ - cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); - cursor[CurResize] = drw_cur_create(drw, XC_sizing); -@@ -1571,6 +1756,8 @@ setup(void) - scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); - for (i = 0; i < LENGTH(colors); i++) - scheme[i] = drw_scm_create(drw, colors[i], 3); -+ /* init system tray */ -+ updatesystray(); - /* init bars */ - updatebars(); - updatestatus(); -@@ -1704,7 +1891,18 @@ togglebar(const Arg *arg) - { - selmon->showbar = !selmon->showbar; - updatebarpos(selmon); -- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); -+ resizebarwin(selmon); -+ if (showsystray) { -+ XWindowChanges wc; -+ if (!selmon->showbar) -+ wc.y = -bh; -+ else if (selmon->showbar) { -+ wc.y = 0; -+ if (!selmon->topbar) -+ wc.y = selmon->mh - bh; -+ } -+ XConfigureWindow(dpy, systray->win, CWY, &wc); -+ } - arrange(selmon); - } - -@@ -1799,11 +1997,18 @@ unmapnotify(XEvent *e) - else - unmanage(c, 0); - } -+ else if ((c = wintosystrayicon(ev->window))) { -+ /* KLUDGE! sometimes icons occasionally unmap their windows, but do -+ * _not_ destroy them. We map those windows back */ -+ XMapRaised(dpy, c->win); -+ updatesystray(); -+ } - } - - void - updatebars(void) - { -+ unsigned int w; - Monitor *m; - XSetWindowAttributes wa = { - .override_redirect = True, -@@ -1814,10 +2019,15 @@ 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), -+ w = m->ww; -+ if (showsystray && m == systraytomon(m)) -+ w -= getsystraywidth(); -+ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen), - CopyFromParent, DefaultVisual(dpy, screen), - CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); - XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); -+ if (showsystray && m == systraytomon(m)) -+ XMapRaised(dpy, systray->win); - XMapRaised(dpy, m->barwin); - XSetClassHint(dpy, m->barwin, &ch); - } -@@ -1993,6 +2203,121 @@ updatestatus(void) - if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) - strcpy(stext, "dwm-"VERSION); - drawbar(selmon); -+ updatesystray(); -+} -+ -+void -+updatesystrayicongeom(Client *i, int w, int h) -+{ -+ if (i) { -+ i->h = bh; -+ if (w == h) -+ i->w = bh; -+ else if (h == bh) -+ i->w = w; -+ else -+ i->w = (int) ((float)bh * ((float)w / (float)h)); -+ applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); -+ /* force icons into the systray dimensions if they don't want to */ -+ if (i->h > bh) { -+ if (i->w == i->h) -+ i->w = bh; -+ else -+ i->w = (int) ((float)bh * ((float)i->w / (float)i->h)); -+ i->h = bh; -+ } -+ } -+} -+ -+void -+updatesystrayiconstate(Client *i, XPropertyEvent *ev) -+{ -+ long flags; -+ int code = 0; -+ -+ if (!showsystray || !i || ev->atom != xatom[XembedInfo] || -+ !(flags = getatomprop(i, xatom[XembedInfo]))) -+ return; -+ -+ if (flags & XEMBED_MAPPED && !i->tags) { -+ i->tags = 1; -+ code = XEMBED_WINDOW_ACTIVATE; -+ XMapRaised(dpy, i->win); -+ setclientstate(i, NormalState); -+ } -+ else if (!(flags & XEMBED_MAPPED) && i->tags) { -+ i->tags = 0; -+ code = XEMBED_WINDOW_DEACTIVATE; -+ XUnmapWindow(dpy, i->win); -+ setclientstate(i, WithdrawnState); -+ } -+ else -+ return; -+ sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0, -+ systray->win, XEMBED_EMBEDDED_VERSION); -+} -+ -+void -+updatesystray(void) -+{ -+ XSetWindowAttributes wa; -+ XWindowChanges wc; -+ Client *i; -+ Monitor *m = systraytomon(NULL); -+ unsigned int x = m->mx + m->mw; -+ unsigned int w = 1; -+ -+ if (!showsystray) -+ return; -+ if (!systray) { -+ /* init systray */ -+ if (!(systray = (Systray *)calloc(1, sizeof(Systray)))) -+ die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); -+ systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel); -+ wa.event_mask = ButtonPressMask | ExposureMask; -+ wa.override_redirect = True; -+ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; -+ XSelectInput(dpy, systray->win, SubstructureNotifyMask); -+ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, -+ PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1); -+ XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa); -+ XMapRaised(dpy, systray->win); -+ XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); -+ if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { -+ sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0); -+ XSync(dpy, False); -+ } -+ else { -+ fprintf(stderr, "dwm: unable to obtain system tray.\n"); -+ free(systray); -+ systray = NULL; -+ return; -+ } -+ } -+ for (w = 0, i = systray->icons; i; i = i->next) { -+ /* make sure the background color stays the same */ -+ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; -+ XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); -+ XMapRaised(dpy, i->win); -+ w += systrayspacing; -+ i->x = w; -+ XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); -+ w += i->w; -+ if (i->mon != m) -+ i->mon = m; -+ } -+ w = w ? w + systrayspacing : 1; -+ x -= w; -+ XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh); -+ wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh; -+ wc.stack_mode = Above; wc.sibling = m->barwin; -+ XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc); -+ XMapWindow(dpy, systray->win); -+ XMapSubwindows(dpy, systray->win); -+ /* redraw background */ -+ XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel); -+ XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); -+ XSync(dpy, False); - } - - void -@@ -2060,6 +2385,16 @@ wintoclient(Window w) - return NULL; - } - -+Client * -+wintosystrayicon(Window w) { -+ Client *i = NULL; -+ -+ if (!showsystray || !w) -+ return i; -+ for (i = systray->icons; i && i->win != w; i = i->next) ; -+ return i; -+} -+ - Monitor * - wintomon(Window w) - { -@@ -2113,6 +2448,22 @@ xerrorstart(Display *dpy, XErrorEvent *ee) - return -1; - } - -+Monitor * -+systraytomon(Monitor *m) { -+ Monitor *t; -+ int i, n; -+ if(!systraypinning) { -+ if(!m) -+ return selmon; -+ return m == selmon ? m : NULL; -+ } -+ for(n = 1, t = mons; t && t->next; n++, t = t->next) ; -+ for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ; -+ if(systraypinningfailfirst && n < systraypinning) -+ return mons; -+ return t; -+} -+ - void - zoom(const Arg *arg) - { diff --git a/suckless/dwm/dwm.1 b/suckless/dwm/dwm.1 index f40bbbba..ddc8321f 100644 --- a/suckless/dwm/dwm.1 +++ b/suckless/dwm/dwm.1 @@ -92,12 +92,6 @@ Sets monocle layout. .B Mod1\-space Toggles between current and previous layout. .TP -.B Mod1\-Control\-, -Cycles backwards in layout list. -.TP -.B Mod1\-Control\-. -Cycles forwards in layout list. -.TP .B Mod1\-j Focus next window. .TP @@ -116,9 +110,6 @@ 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/suckless/dwm/dwm.c b/suckless/dwm/dwm.c index dcf0e94b..599fa3d5 100644 --- a/suckless/dwm/dwm.c +++ b/suckless/dwm/dwm.c @@ -40,48 +40,255 @@ #include #endif /* XINERAMA */ #include -#include -#include +#include "patches.h" #include "drw.h" #include "util.h" +#if BAR_FLEXWINTITLE_PATCH +#ifndef FLEXTILE_DELUXE_LAYOUT +#define FLEXTILE_DELUXE_LAYOUT 1 +#endif +#endif + +#if BAR_PANGO_PATCH +#include +#endif // BAR_PANGO_PATCH + +#if SPAWNCMD_PATCH +#include +#include +#include +#define SPAWN_CWD_DELIM " []{}()<>\"':" +#endif // SPAWNCMD_PATCH + /* macros */ +#define Button6 6 +#define Button7 7 +#define Button8 8 +#define Button9 9 +#define NUMTAGS 9 +#define BARRULES 20 #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) +#if BAR_ANYBAR_PATCH +#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->mx+(m)->mw) - MAX((x),(m)->mx)) \ + * MAX(0, MIN((y)+(h),(m)->my+(m)->mh) - MAX((y),(m)->my))) +#else #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))) +#endif // BAR_ANYBAR_PATCH +#if ATTACHASIDE_PATCH && STICKY_PATCH +#define ISVISIBLEONTAG(C, T) ((C->tags & T) || C->issticky) +#define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags]) +#elif ATTACHASIDE_PATCH +#define ISVISIBLEONTAG(C, T) ((C->tags & T)) +#define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags]) +#elif STICKY_PATCH +#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]) || C->issticky) +#else #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) +#endif // ATTACHASIDE_PATCH #define LENGTH(X) (sizeof X / sizeof X[0]) #define MOUSEMASK (BUTTONMASK|PointerMotionMask) -#define WIDTH(X) ((X)->w + 2 * (X)->bw + gappx) -#define HEIGHT(X) ((X)->h + 2 * (X)->bw + gappx) -#define TAGMASK ((1 << LENGTH(tags)) - 1) -#define TAGSLENGTH (LENGTH(tags)) -#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) -#define TTEXTW(X) drw_fontset_getwidth(drw, (X)) - -#define DWMBLOCKSLOCKFILE "/tmp/dwmblocks.pid" +#define WIDTH(X) ((X)->w + 2 * (X)->bw) +#define HEIGHT(X) ((X)->h + 2 * (X)->bw) +#define WTYPE "_NET_WM_WINDOW_TYPE_" +#if SCRATCHPADS_PATCH +#define TOTALTAGS (NUMTAGS + LENGTH(scratchpads)) +#define TAGMASK ((1 << TOTALTAGS) - 1) +#define SPTAG(i) ((1 << NUMTAGS) << (i)) +#define SPTAGMASK (((1 << LENGTH(scratchpads))-1) << NUMTAGS) +#else +#define TAGMASK ((1 << NUMTAGS) - 1) +#endif // SCRATCHPADS_PATCH +#define TEXTWM(X) (drw_fontset_getwidth(drw, (X), True) + lrpad) +#define TEXTW(X) (drw_fontset_getwidth(drw, (X), False) + lrpad) +#define HIDDEN(C) ((getstate(C->win) == IconicState)) /* enums */ -enum { CurNormal, CurHand, CurResize, CurMove, CurLast }; /* cursor */ -enum { SchemeNorm, SchemeSel, SchemeStatus, SchemeTagsSel, SchemeTagsNorm, SchemeInfoSel, SchemeInfoNorm, SchemeCol1, SchemeCol2, SchemeCol3, - SchemeCol4, SchemeCol5, SchemeCol6, SchemeCol7, SchemeCol8, - SchemeCol9, SchemeCol10, SchemeCol11, SchemeCol12 }; /* color schemes */ -enum { NetSupported, NetWMName, NetWMState, NetWMCheck, - NetWMFullscreen, NetActiveWindow, NetWMWindowType, - NetWMWindowTypeDialog, NetClientList, NetClientListStacking, NetDesktopNames, NetDesktopViewport, NetNumberOfDesktops, NetCurrentDesktop, NetLast }; /* EWMH atoms */ -enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ -enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, - ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ +enum { + #if RESIZEPOINT_PATCH || RESIZECORNERS_PATCH + CurResizeBR, + CurResizeBL, + CurResizeTR, + CurResizeTL, + #endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH + #if DRAGMFACT_PATCH + CurResizeHorzArrow, + CurResizeVertArrow, + #endif // DRAGMFACT_PATCH + #if DRAGCFACT_PATCH + CurIronCross, + #endif // DRAGCFACT_PATCH + CurNormal, + CurResize, + CurMove, + CurLast +}; /* cursor */ + +enum { + SchemeNorm, + SchemeSel, + SchemeTitleNorm, + SchemeTitleSel, + SchemeTagsNorm, + SchemeTagsSel, + SchemeHid, + SchemeUrg, + #if BAR_FLEXWINTITLE_PATCH + SchemeFlexActTTB, + SchemeFlexActLTR, + SchemeFlexActMONO, + SchemeFlexActGRID, + SchemeFlexActGRD1, + SchemeFlexActGRD2, + SchemeFlexActGRDM, + SchemeFlexActHGRD, + SchemeFlexActDWDL, + SchemeFlexActSPRL, + SchemeFlexInaTTB, + SchemeFlexInaLTR, + SchemeFlexInaMONO, + SchemeFlexInaGRID, + SchemeFlexInaGRD1, + SchemeFlexInaGRD2, + SchemeFlexInaGRDM, + SchemeFlexInaHGRD, + SchemeFlexInaDWDL, + SchemeFlexInaSPRL, + SchemeFlexSelTTB, + SchemeFlexSelLTR, + SchemeFlexSelMONO, + SchemeFlexSelGRID, + SchemeFlexSelGRD1, + SchemeFlexSelGRD2, + SchemeFlexSelGRDM, + SchemeFlexSelHGRD, + SchemeFlexSelDWDL, + SchemeFlexSelSPRL, + SchemeFlexActFloat, + SchemeFlexInaFloat, + SchemeFlexSelFloat, + #endif // BAR_FLEXWINTITLE_PATCH +}; /* color schemes */ + +enum { + NetSupported, NetWMName, NetWMState, NetWMCheck, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + #if BAR_SYSTRAY_PATCH + NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, + NetSystemTrayVisual, NetWMWindowTypeDock, NetSystemTrayOrientationHorz, + #endif // BAR_SYSTRAY_PATCH + #if BAR_EWMHTAGS_PATCH + NetDesktopNames, NetDesktopViewport, NetNumberOfDesktops, NetCurrentDesktop, + #endif // BAR_EWMHTAGS_PATCH + NetClientList, + #if NET_CLIENT_LIST_STACKING_PATCH + NetClientListStacking, + #endif // NET_CLIENT_LIST_STACKING_PATCH + NetLast +}; /* EWMH atoms */ + +enum { + WMProtocols, + WMDelete, + WMState, + WMTakeFocus, + #if WINDOWROLERULE_PATCH + WMWindowRole, + #endif // WINDOWROLERULE_PATCH + WMLast +}; /* default atoms */ + +enum { + #if BAR_STATUSBUTTON_PATCH + ClkButton, + #endif // BAR_STATUSBUTTON_PATCH + ClkTagBar, + ClkLtSymbol, + ClkStatusText, + ClkWinTitle, + ClkClientWin, + ClkRootWin, + ClkLast +}; /* clicks */ + +enum { + BAR_ALIGN_LEFT, + BAR_ALIGN_CENTER, + BAR_ALIGN_RIGHT, + BAR_ALIGN_LEFT_LEFT, + BAR_ALIGN_LEFT_RIGHT, + BAR_ALIGN_LEFT_CENTER, + BAR_ALIGN_NONE, + BAR_ALIGN_RIGHT_LEFT, + BAR_ALIGN_RIGHT_RIGHT, + BAR_ALIGN_RIGHT_CENTER, + BAR_ALIGN_LAST +}; /* bar alignment */ + +#if IPC_PATCH +typedef struct TagState TagState; +struct TagState { + int selected; + int occupied; + int urgent; +}; + +typedef struct ClientState ClientState; +struct ClientState { + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; +}; +#endif // IPC_PATCH typedef union { + #if IPC_PATCH + long i; + unsigned long ui; + #else int i; unsigned int ui; + #endif // IPC_PATCH float f; const void *v; } Arg; +typedef struct Monitor Monitor; +typedef struct Bar Bar; +struct Bar { + Window win; + Monitor *mon; + Bar *next; + int idx; + int showbar; + int topbar; + int external; + int borderpx; + int borderscheme; + int bx, by, bw, bh; /* bar geometry */ + int w[BARRULES]; // width, array length == barrules, then use r index for lookup purposes + int x[BARRULES]; // x position, array length == ^ +}; + +typedef struct { + int x; + int y; + int h; + int w; +} BarArg; + +typedef struct { + int monitor; + int bar; + int alignment; // see bar alignment enum + int (*widthfunc)(Bar *bar, BarArg *a); + int (*drawfunc)(Bar *bar, BarArg *a); + int (*clickfunc)(Bar *bar, Arg *arg, BarArg *a); + char *name; // for debugging + int x, w; // position, width for internal use +} BarRule; + typedef struct { unsigned int click; unsigned int mask; @@ -90,22 +297,70 @@ typedef struct { const Arg arg; } Button; -typedef struct Monitor Monitor; typedef struct Client Client; struct Client { char name[256]; float mina, maxa; + #if CFACTS_PATCH float cfact; + #endif // CFACTS_PATCH int x, y, w, h; + #if SAVEFLOATS_PATCH || EXRESIZE_PATCH + int sfx, sfy, sfw, sfh; /* stored float geometry, used on mode revert */ + #endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH int oldx, oldy, oldw, oldh; int basew, baseh, incw, inch, maxw, maxh, minw, minh; int bw, oldbw; unsigned int tags; + #if SWITCHTAG_PATCH + unsigned int switchtag; + #endif // SWITCHTAG_PATCH int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; + #if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH + int fakefullscreen; + #endif // FAKEFULLSCREEN_CLIENT_PATCH + #if EXRESIZE_PATCH + unsigned char expandmask; + int expandx1, expandy1, expandx2, expandy2; + #if !MAXIMIZE_PATCH + int wasfloating; + #endif // MAXIMIZE_PATCH + #endif // EXRESIZE_PATCH + #if MAXIMIZE_PATCH + int ismax, wasfloating; + #endif // MAXIMIZE_PATCH + #if AUTORESIZE_PATCH + int needresize; + #endif // AUTORESIZE_PATCH + #if CENTER_PATCH + int iscentered; + #endif // CENTER_PATCH + #if ISPERMANENT_PATCH + int ispermanent; + #endif // ISPERMANENT_PATCH + #if PLACEMOUSE_PATCH + int beingmoved; + #endif // PLACEMOUSE_PATCH + #if SWALLOW_PATCH + int isterminal, noswallow; + pid_t pid; + #endif // SWALLOW_PATCH + #if STEAM_PATCH + int issteam; + #endif // STEAM_PATCH + #if STICKY_PATCH + int issticky; + #endif // STICKY_PATCH Client *next; Client *snext; + #if SWALLOW_PATCH + Client *swallowing; + #endif // SWALLOW_PATCH Monitor *mon; Window win; + #if IPC_PATCH + ClientState prevstate; + #endif // IPC_PATCH }; typedef struct { @@ -115,44 +370,164 @@ typedef struct { const Arg arg; } Key; +#if FLEXTILE_DELUXE_LAYOUT +typedef struct { + int nmaster; + int nstack; + int layout; + int masteraxis; // master stack area + int stack1axis; // primary stack area + int stack2axis; // secondary stack area, e.g. centered master + void (*symbolfunc)(Monitor *, unsigned int); +} LayoutPreset; +#endif // FLEXTILE_DELUXE_LAYOUT + typedef struct { const char *symbol; void (*arrange)(Monitor *); + #if FLEXTILE_DELUXE_LAYOUT + LayoutPreset preset; + #endif // FLEXTILE_DELUXE_LAYOUT } Layout; +#if INSETS_PATCH +typedef struct { + int x; + int y; + int w; + int h; +} Inset; +#endif // INSETS_PATCH + +#if PERTAG_PATCH typedef struct Pertag Pertag; +#endif // PERTAG_PATCH struct Monitor { + int index; char ltsymbol[16]; float mfact; + #if FLEXTILE_DELUXE_LAYOUT + int ltaxis[4]; + int nstack; + #endif // FLEXTILE_DELUXE_LAYOUT int nmaster; int num; - int by; /* bar geometry */ int mx, my, mw, mh; /* screen size */ int wx, wy, ww, wh; /* window area */ + #if VANITYGAPS_PATCH + int gappih; /* horizontal gap between windows */ + int gappiv; /* vertical gap between windows */ + int gappoh; /* horizontal outer gaps */ + int gappov; /* vertical outer gaps */ + #endif // VANITYGAPS_PATCH + #if SETBORDERPX_PATCH + unsigned int borderpx; + #endif // SETBORDERPX_PATCH unsigned int seltags; unsigned int sellt; unsigned int tagset[2]; - int rmaster; int showbar; - int topbar; Client *clients; Client *sel; Client *stack; Monitor *next; - Window barwin; + Bar *bar; const Layout *lt[2]; + #if BAR_ALTERNATIVE_TAGS_PATCH + unsigned int alttag; + #endif // BAR_ALTERNATIVE_TAGS_PATCH + #if PERTAG_PATCH Pertag *pertag; + #endif // PERTAG_PATCH + #if INSETS_PATCH + Inset inset; + #endif // INSETS_PATCH + #if IPC_PATCH + char lastltsymbol[16]; + TagState tagstate; + Client *lastsel; + const Layout *lastlt; + #endif // IPC_PATCH }; typedef struct { const char *class; + #if WINDOWROLERULE_PATCH + const char *role; + #endif // WINDOWROLERULE_PATCH const char *instance; const char *title; + const char *wintype; unsigned int tags; + #if SWITCHTAG_PATCH + int switchtag; + #endif // SWITCHTAG_PATCH + #if CENTER_PATCH + int iscentered; + #endif // CENTER_PATCH int isfloating; + #if SELECTIVEFAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH + int isfakefullscreen; + #endif // SELECTIVEFAKEFULLSCREEN_PATCH + #if ISPERMANENT_PATCH + int ispermanent; + #endif // ISPERMANENT_PATCH + #if SWALLOW_PATCH + int isterminal; + int noswallow; + #endif // SWALLOW_PATCH + #if FLOATPOS_PATCH + const char *floatpos; + #endif // FLOATPOS_PATCH int monitor; } Rule; +#define RULE(...) { .monitor = -1, ##__VA_ARGS__ }, + +/* Cross patch compatibility rule macro helper macros */ +#define FLOATING , .isfloating = 1 +#if CENTER_PATCH +#define CENTERED , .iscentered = 1 +#else +#define CENTERED +#endif // CENTER_PATCH +#if ISPERMANENT_PATCH +#define PERMANENT , .ispermanent = 1 +#else +#define PERMANENT +#endif // ISPERMANENT_PATCH +#if SELECTIVEFAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH +#define FAKEFULLSCREEN , .isfakefullscreen = 1 +#else +#define FAKEFULLSCREEN +#endif // SELECTIVEFAKEFULLSCREEN_PATCH +#if SWALLOW_PATCH +#define NOSWALLOW , .noswallow = 1 +#define TERMINAL , .isterminal = 1 +#else +#define NOSWALLOW +#define TERMINAL +#endif // SWALLOW_PATCH +#if SWITCHTAG_PATCH +#define SWITCHTAG , .switchtag = 1 +#else +#define SWITCHTAG +#endif // SWITCHTAG_PATCH + +#if MONITOR_RULES_PATCH +typedef struct { + int monitor; + #if PERTAG_PATCH + int tag; + #endif // PERTAG_PATCH + int layout; + float mfact; + int nmaster; + int showbar; + int topbar; +} MonitorRule; +#endif // MONITOR_RULES_PATCH + /* function declarations */ static void applyrules(Client *c); static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); @@ -169,38 +544,51 @@ static void configure(Client *c); static void configurenotify(XEvent *e); static void configurerequest(XEvent *e); static Monitor *createmon(void); -static void cyclelayout(const Arg *arg); -static void deck(Monitor *m); static void destroynotify(XEvent *e); static void detach(Client *c); static void detachstack(Client *c); static Monitor *dirtomon(int dir); static void drawbar(Monitor *m); static void drawbars(void); +static void drawbarwin(Bar *bar); +#if !FOCUSONCLICK_PATCH static void enternotify(XEvent *e); +#endif // FOCUSONCLICK_PATCH static void expose(XEvent *e); static void focus(Client *c); static void focusin(XEvent *e); static void focusmon(const Arg *arg); +#if !STACKER_PATCH static void focusstack(const Arg *arg); +#endif // STACKER_PATCH static Atom getatomprop(Client *c, Atom prop); static int getrootptr(int *x, int *y); static long getstate(Window w); static int gettextprop(Window w, Atom atom, char *text, unsigned int size); static void grabbuttons(Client *c, int focused); +#if KEYMODES_PATCH +static void grabdefkeys(void); +#else static void grabkeys(void); +#endif // KEYMODES_PATCH static void incnmaster(const Arg *arg); -static void inplacerotate(const Arg *arg); +#if KEYMODES_PATCH +static void keydefpress(XEvent *e); +#else static void keypress(XEvent *e); +#endif // KEYMODES_PATCH static void killclient(const Arg *arg); static void manage(Window w, XWindowAttributes *wa); static void mappingnotify(XEvent *e); static void maprequest(XEvent *e); -static void monocle(Monitor *m); +#if !FOCUSONCLICK_PATCH static void motionnotify(XEvent *e); +#endif // FOCUSONCLICK_PATCH static void movemouse(const Arg *arg); static Client *nexttiled(Client *c); +#if !ZOOMSWAP_PATCH || TAGINTOSTACK_ALLMASTER_PATCH || TAGINTOSTACK_ONEMASTER_PATCH static void pop(Client *); +#endif // !ZOOMSWAP_PATCH / TAGINTOSTACK_ALLMASTER_PATCH / TAGINTOSTACK_ONEMASTER_PATCH static void propertynotify(XEvent *e); static void quit(const Arg *arg); static Monitor *recttomon(int x, int y, int w, int h); @@ -210,91 +598,136 @@ static void resizemouse(const Arg *arg); static void restack(Monitor *m); static void run(void); static void scan(void); +#if BAR_SYSTRAY_PATCH +static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); +#else static int sendevent(Client *c, Atom proto); +#endif // BAR_SYSTRAY_PATCH static void sendmon(Client *c, Monitor *m); static void setclientstate(Client *c, long state); -static void setcurrentdesktop(void); -static void setdesktopnames(void); 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 setnumdesktops(void); static void setup(void); -static void setviewport(void); static void seturgent(Client *c, int urg); static void showhide(Client *c); static void sigchld(int unused); -static void sigdwmblocks(const Arg *arg); static void spawn(const Arg *arg); -static void switchcol(const Arg *arg); +#if RIODRAW_PATCH +static pid_t spawncmd(const Arg *arg); +#endif // RIODRAW_PATCH 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 togglermaster(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); +static void unfocus(Client *c, int setfocus, Client *nextfocus); static void unmanage(Client *c, int destroyed); static void unmapnotify(XEvent *e); -static void updatecurrentdesktop(void); -static void updatebarcursor(int cursorpos); static void updatebarpos(Monitor *m); static void updatebars(void); static void updateclientlist(void); -static void updatedwmblockssig(int x, int e); 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 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); static void zoom(const Arg *arg); -static void centeredmaster(Monitor *m); -static void centeredfloatingmaster(Monitor *m); + +/* bar functions */ + +#include "patch/include.h" /* variables */ static const char broken[] = "broken"; -static char stextc[256]; -static char stexts[256]; -static int wstext; -static int dwmblockssig; +#if BAR_PANGO_PATCH || BAR_STATUS2D_PATCH && !BAR_STATUSCOLORS_PATCH +static char stext[1024]; +#else +static char stext[512]; +#endif // BAR_PANGO_PATCH | BAR_STATUS2D_PATCH +#if BAR_EXTRASTATUS_PATCH || BAR_STATUSCMD_PATCH +#if BAR_STATUS2D_PATCH +static char rawstext[1024]; +#else +static char rawstext[512]; +#endif // BAR_STATUS2D_PATCH +#endif // BAR_EXTRASTATUS_PATCH | BAR_STATUSCMD_PATCH +#if BAR_EXTRASTATUS_PATCH +#if BAR_STATUS2D_PATCH && !BAR_STATUSCOLORS_PATCH +static char estext[1024]; +#else +static char estext[512]; +#endif // BAR_STATUS2D_PATCH +#if BAR_STATUSCMD_PATCH +static char rawestext[1024]; +#endif // BAR_STATUS2D_PATCH | BAR_STATUSCMD_PATCH +#endif // BAR_EXTRASTATUS_PATCH + static int screen; static int sw, sh; /* X display screen geometry width, height */ -static int bh, blw = 0; /* bar geometry */ +static int bh; /* 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 */ +/* Some clients (e.g. alacritty) helpfully send configure requests with a new size or position + * when they detect that they have been moved to another monitor. This can cause visual glitches + * when moving (or resizing) client windows from one monitor to another. This variable is used + * internally to ignore such configure requests while movemouse or resizemouse are being used. */ +static int ignoreconfigurerequests = 0; +#if WARP_PATCH +static int force_warp = 0; // force warp in some situations, e.g. killclient +static int ignore_warp = 0; // force skip warp in some situations, e.g. dragmfact, dragcfact +#endif // WARP_PATCH static int (*xerrorxlib)(Display *, XErrorEvent *); static unsigned int numlockmask = 0; +#if RIODRAW_PATCH +static int riodimensions[4] = { -1, -1, -1, -1 }; +static pid_t riopid = 0; +#endif // RIODRAW_PATCH static void (*handler[LASTEvent]) (XEvent *) = { [ButtonPress] = buttonpress, + #if COMBO_PATCH || BAR_HOLDBAR_PATCH + [ButtonRelease] = keyrelease, + #endif // COMBO_PATCH / BAR_HOLDBAR_PATCH [ClientMessage] = clientmessage, [ConfigureRequest] = configurerequest, [ConfigureNotify] = configurenotify, [DestroyNotify] = destroynotify, + #if !FOCUSONCLICK_PATCH + [EnterNotify] = enternotify, + #endif // FOCUSONCLICK_PATCH [Expose] = expose, [FocusIn] = focusin, [KeyPress] = keypress, + #if COMBO_PATCH || BAR_HOLDBAR_PATCH + [KeyRelease] = keyrelease, + #endif // COMBO_PATCH / BAR_HOLDBAR_PATCH [MappingNotify] = mappingnotify, [MapRequest] = maprequest, + #if !FOCUSONCLICK_PATCH [MotionNotify] = motionnotify, + #endif // FOCUSONCLICK_PATCH [PropertyNotify] = propertynotify, + #if BAR_SYSTRAY_PATCH + [ResizeRequest] = resizerequest, + #endif // BAR_SYSTRAY_PATCH [UnmapNotify] = unmapnotify }; +#if BAR_SYSTRAY_PATCH +static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; +#else static Atom wmatom[WMLast], netatom[NetLast]; +#endif // BAR_SYSTRAY_PATCH +#if ON_EMPTY_KEYS_PATCH +static int isempty = 0; +#endif // ON_EMPTY_KEYS_PATCH static int running = 1; static Cur *cursor[CurLast]; static Clr **scheme; @@ -304,55 +737,162 @@ static Monitor *mons, *selmon; static Window root, wmcheckwin; /* configuration, allows nested code to access above variables */ + #include "config.h" +#include "theme.h" +#include "rules.h" +#include "keybind.h" + +#include "patch/include.c" -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 */ -}; /* compile-time check if all tags fit into an unsigned int bit array. */ -struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; +#if SCRATCHPAD_ALT_1_PATCH +struct NumTags { char limitexceeded[NUMTAGS > 30 ? -1 : 1]; }; +#else +struct NumTags { char limitexceeded[NUMTAGS > 31 ? -1 : 1]; }; +#endif // SCRATCHPAD_ALT_1_PATCH /* function implementations */ void applyrules(Client *c) { const char *class, *instance; + Atom wintype; + #if WINDOWROLERULE_PATCH + char role[64]; + #endif // WINDOWROLERULE_PATCH unsigned int i; + #if SWITCHTAG_PATCH + unsigned int newtagset; + #endif // SWITCHTAG_PATCH const Rule *r; Monitor *m; XClassHint ch = { NULL, NULL }; /* rule matching */ + #if SWALLOW_PATCH + c->noswallow = -1; + #endif // SWALLOW_PATCH c->isfloating = 0; c->tags = 0; XGetClassHint(dpy, c->win, &ch); class = ch.res_class ? ch.res_class : broken; instance = ch.res_name ? ch.res_name : broken; + wintype = getatomprop(c, netatom[NetWMWindowType]); + #if WINDOWROLERULE_PATCH + gettextprop(c->win, wmatom[WMWindowRole], role, sizeof(role)); + #endif // WINDOWROLERULE_PATCH + + #if STEAM_PATCH + if (strstr(class, "Steam") || strstr(class, "steam_app_")) + c->issteam = 1; + #endif // STEAM_PATCH 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))) + #if WINDOWROLERULE_PATCH + && (!r->role || strstr(role, r->role)) + #endif // WINDOWROLERULE_PATCH + && (!r->instance || strstr(instance, r->instance)) + && (!r->wintype || wintype == XInternAtom(dpy, r->wintype, False))) { + #if CENTER_PATCH + c->iscentered = r->iscentered; + #endif // CENTER_PATCH + #if ISPERMANENT_PATCH + c->ispermanent = r->ispermanent; + #endif // ISPERMANENT_PATCH + #if SELECTIVEFAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH + c->fakefullscreen = r->isfakefullscreen; + #endif // SELECTIVEFAKEFULLSCREEN_PATCH + #if SWALLOW_PATCH + c->isterminal = r->isterminal; + c->noswallow = r->noswallow; + #endif // SWALLOW_PATCH c->isfloating = r->isfloating; c->tags |= r->tags; + #if SCRATCHPADS_PATCH + 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); + } + #endif // SCRATCHPADS_PATCH for (m = mons; m && m->num != r->monitor; m = m->next); if (m) c->mon = m; + #if FLOATPOS_PATCH + if (c->isfloating && r->floatpos) { + #if CENTER_PATCH + c->iscentered = 0; + #endif // CENTER_PATCH + setfloatpos(c, r->floatpos); + } + #endif // FLOATPOS_PATCH + + #if SWITCHTAG_PATCH + #if SWALLOW_PATCH + if (r->switchtag && ( + c->noswallow > 0 || + !termforwin(c) || + !(c->isfloating && swallowfloating && c->noswallow < 0))) + #else + if (r->switchtag) + #endif // SWALLOW_PATCH + { + selmon = c->mon; + if (r->switchtag == 2 || r->switchtag == 4) + newtagset = c->mon->tagset[c->mon->seltags] ^ c->tags; + else + newtagset = c->tags; + + /* Switch to the client's tag, but only if that tag is not already shown */ + if (newtagset && !(c->tags & c->mon->tagset[c->mon->seltags])) { + if (r->switchtag == 3 || r->switchtag == 4) + c->switchtag = c->mon->tagset[c->mon->seltags]; + if (r->switchtag == 1 || r->switchtag == 3) { + #if PERTAG_PATCH + pertagview(&((Arg) { .ui = newtagset })); + arrange(c->mon); + #else + view(&((Arg) { .ui = newtagset })); + #endif // PERTAG_PATCH + } else { + c->mon->tagset[c->mon->seltags] = newtagset; + arrange(c->mon); + } + } + } + #endif // SWITCHTAG_PATCH + #if ONLY_ONE_RULE_MATCH_PATCH + break; + #endif // ONLY_ONE_RULE_MATCH_PATCH } } if (ch.res_class) XFree(ch.res_class); if (ch.res_name) XFree(ch.res_name); + #if EMPTYVIEW_PATCH + if (c->tags & TAGMASK) c->tags = c->tags & TAGMASK; + #if SCRATCHPADS_PATCH + else if (c->mon->tagset[c->mon->seltags]) c->tags = c->mon->tagset[c->mon->seltags] & ~SPTAGMASK; + #elif SCRATCHPAD_ALT_1_PATCH + else if (c->tags != SCRATCHPAD_MASK && c->mon->tagset[c->mon->seltags]) c->tags = c->mon->tagset[c->mon->seltags]; + #else + else if (c->mon->tagset[c->mon->seltags]) c->tags = c->mon->tagset[c->mon->seltags]; + #endif // SCRATCHPADS_PATCH + else c->tags = 1; + #elif SCRATCHPADS_PATCH + c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : (c->mon->tagset[c->mon->seltags] & ~SPTAGMASK); + #elif SCRATCHPAD_ALT_1_PATCH + if (c->tags != SCRATCHPAD_MASK) + c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; + #else c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; + #endif // EMPTYVIEW_PATCH } int @@ -441,6 +981,11 @@ 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); + #if ROUNDED_CORNERS_PATCH + Client *c; + for (c = nexttiled(m->clients); c; c = nexttiled(c->next)) + drawroundedcorners(c); + #endif // ROUNDED_CORNERS_PATCH } void @@ -460,47 +1005,71 @@ attachstack(Client *c) void buttonpress(XEvent *e) { - unsigned int i, x, click; + int click, i, r; Arg arg = {0}; Client *c; Monitor *m; + Bar *bar; XButtonPressedEvent *ev = &e->xbutton; - + const BarRule *br; + BarArg carg = { 0, 0, 0, 0 }; click = ClkRootWin; /* focus monitor if necessary */ - if ((m = wintomon(ev->window)) && m != selmon) { - unfocus(selmon->sel, 1); + if ((m = wintomon(ev->window)) && m != selmon + #if FOCUSONCLICK_PATCH + && (focusonwheel || (ev->button != Button4 && ev->button != Button5)) + #endif // FOCUSONCLICK_PATCH + ) { + unfocus(selmon->sel, 1, NULL); selmon = m; focus(NULL); } - 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 + blw) - click = ClkLtSymbol; - else if (ev->x < selmon->ww - wstext) - click = ClkWinTitle; -// else if (ev->x < selmon->ww - lrpad / 2 && ev->x >= (x = selmon->ww - wstext + lrpad / 2)) { - else if (ev->x < selmon->ww - lrpad / 2 && ev->x >= selmon->ww - wstext + lrpad / 2) { - click = ClkStatusText; -// updatedwmblockssig(x, ev->x); - } else - return; - } else if ((c = wintoclient(ev->window))) { + + for (bar = selmon->bar; bar; bar = bar->next) { + if (ev->window == bar->win) { + for (r = 0; r < LENGTH(barrules); r++) { + br = &barrules[r]; + if (br->bar != bar->idx || (br->monitor == 'A' && m != selmon) || br->clickfunc == NULL) + continue; + if (br->monitor != 'A' && br->monitor != -1 && br->monitor != bar->mon->index) + continue; + if (bar->x[r] <= ev->x && ev->x <= bar->x[r] + bar->w[r]) { + carg.x = ev->x - bar->x[r]; + carg.y = ev->y - bar->borderpx; + carg.w = bar->w[r]; + carg.h = bar->bh - 2 * bar->borderpx; + click = br->clickfunc(bar, &arg, &carg); + if (click < 0) + return; + break; + } + } + break; + } + } + + if (click == ClkRootWin && (c = wintoclient(ev->window))) { + #if FOCUSONCLICK_PATCH + if (focusonwheel || (ev->button != Button4 && ev->button != Button5)) + focus(c); + #else focus(c); restack(selmon); + #endif // FOCUSONCLICK_PATCH XAllowEvents(dpy, ReplayPointer, CurrentTime); click = ClkClientWin; } - for (i = 0; i < LENGTH(buttons); i++) + + 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)) + && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) { + #if BAR_WINTITLEACTIONS_PATCH + buttons[i].func((click == ClkTagBar || click == ClkWinTitle) && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); + #else buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); + #endif // BAR_WINTITLEACTIONS_PATCH + } + } } void @@ -521,7 +1090,6 @@ cleanup(void) Layout foo = { "", NULL }; Monitor *m; size_t i; - view(&a); selmon->lt[selmon->sellt] = &foo; for (m = mons; m; m = m->next) @@ -530,21 +1098,43 @@ cleanup(void) XUngrabKey(dpy, AnyKey, AnyModifier, root); while (mons) cleanupmon(mons); + #if BAR_SYSTRAY_PATCH + if (showsystray && systray) { + if (systray->win) { + XUnmapWindow(dpy, systray->win); + XDestroyWindow(dpy, systray->win); + } + free(systray); + } + #endif // BAR_SYSTRAY_PATCH for (i = 0; i < CurLast; i++) drw_cur_free(drw, cursor[i]); + #if BAR_STATUS2D_PATCH && !BAR_STATUSCOLORS_PATCH + for (i = 0; i < LENGTH(colors) + 1; i++) + #else for (i = 0; i < LENGTH(colors); i++) + #endif // BAR_STATUS2D_PATCH 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 IPC_PATCH + ipc_cleanup(); + + if (close(epoll_fd) < 0) + fprintf(stderr, "Failed to close epoll file descriptor\n"); + #endif // IPC_PATCH } void cleanupmon(Monitor *mon) { Monitor *m; + Bar *bar; if (mon == mons) mons = mons->next; @@ -552,27 +1142,111 @@ cleanupmon(Monitor *mon) for (m = mons; m && m->next != mon; m = m->next); m->next = mon->next; } - XUnmapWindow(dpy, mon->barwin); - XDestroyWindow(dpy, mon->barwin); + for (bar = mon->bar; bar; bar = mon->bar) { + if (!bar->external) { + XUnmapWindow(dpy, bar->win); + XDestroyWindow(dpy, bar->win); + } + mon->bar = bar->next; + #if BAR_SYSTRAY_PATCH + if (systray && bar == systray->bar) + systray->bar = NULL; + #endif // BAR_SYSTRAY_PATCH + free(bar); + } free(mon); } void clientmessage(XEvent *e) { + #if BAR_SYSTRAY_PATCH + XWindowAttributes wa; + XSetWindowAttributes swa; + #endif // BAR_SYSTRAY_PATCH XClientMessageEvent *cme = &e->xclient; Client *c = wintoclient(cme->window); + #if FOCUSONNETACTIVE_PATCH + unsigned int i; + #endif // FOCUSONNETACTIVE_PATCH + + #if BAR_SYSTRAY_PATCH + if (showsystray && systray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { + /* add systray icons */ + if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { + if (!(c = (Client *)calloc(1, sizeof(Client)))) + die("fatal: could not malloc() %u bytes\n", sizeof(Client)); + if (!(c->win = cme->data.l[2])) { + free(c); + return; + } + + c->mon = selmon; + c->next = systray->icons; + systray->icons = c; + XGetWindowAttributes(dpy, c->win, &wa); + c->x = c->oldx = c->y = c->oldy = 0; + c->w = c->oldw = wa.width; + c->h = c->oldh = wa.height; + c->oldbw = wa.border_width; + c->bw = 0; + c->isfloating = True; + /* reuse tags field as mapped status */ + c->tags = 1; + updatesizehints(c); + updatesystrayicongeom(c, wa.width, wa.height); + XAddToSaveSet(dpy, c->win); + XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); + XClassHint ch = {"dwmsystray", "dwmsystray"}; + XSetClassHint(dpy, c->win, &ch); + XReparentWindow(dpy, c->win, systray->win, 0, 0); + /* use parents background color */ + swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; + XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); + sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION); + XSync(dpy, False); + setclientstate(c, NormalState); + } + return; + } + #endif // BAR_SYSTRAY_PATCH if (!c) return; if (cme->message_type == netatom[NetWMState]) { if (cme->data.l[1] == netatom[NetWMFullscreen] - || cme->data.l[2] == netatom[NetWMFullscreen]) + || cme->data.l[2] == netatom[NetWMFullscreen]) { + #if FAKEFULLSCREEN_CLIENT_PATCH + if (c->fakefullscreen == 2 && c->isfullscreen) + c->fakefullscreen = 3; + #endif // FAKEFULLSCREEN_CLIENT_PATCH setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */ - || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen))); + || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ + #if !FAKEFULLSCREEN_PATCH + && !c->isfullscreen + #endif // !FAKEFULLSCREEN_PATCH + ))); + } } else if (cme->message_type == netatom[NetActiveWindow]) { + #if FOCUSONNETACTIVE_PATCH + if (c->tags & c->mon->tagset[c->mon->seltags]) + focus(c); + else { + for (i = 0; i < NUMTAGS && !((1 << i) & c->tags); i++); + if (i < NUMTAGS) { + if (c != selmon->sel) + unfocus(selmon->sel, 0, NULL); + selmon = c->mon; + if (((1 << i) & TAGMASK) != selmon->tagset[selmon->seltags]) + view(&((Arg) { .ui = 1 << i })); + focus(c); + restack(selmon); + } + } + #else if (c != selmon->sel && !c->isurgent) seturgent(c, 1); + #endif // FOCUSONNETACTIVE_PATCH } } @@ -599,23 +1273,32 @@ void configurenotify(XEvent *e) { Monitor *m; + Bar *bar; + #if !FAKEFULLSCREEN_PATCH Client *c; + #endif // !FAKEFULLSCREEN_PATCH 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); + drw_resize(drw, sw, sh); updatebars(); for (m = mons; m; m = m->next) { + #if !FAKEFULLSCREEN_PATCH for (c = m->clients; c; c = c->next) + #if FAKEFULLSCREEN_CLIENT_PATCH + if (c->isfullscreen && c->fakefullscreen != 1) + #else if (c->isfullscreen) + #endif // FAKEFULLSCREEN_CLIENT_PATCH 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); + #endif // !FAKEFULLSCREEN_PATCH + for (bar = m->bar; bar; bar = bar->next) + XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh); } focus(NULL); arrange(NULL); @@ -628,14 +1311,32 @@ configurerequest(XEvent *e) { Client *c; Monitor *m; + #if BAR_ANYBAR_PATCH + Bar *bar; + #endif // BAR_ANYBAR_PATCH XConfigureRequestEvent *ev = &e->xconfigurerequest; XWindowChanges wc; + if (ignoreconfigurerequests) + return; + 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 STEAM_PATCH + if (!c->issteam) { + 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; + } + } + #else if (ev->value_mask & CWX) { c->oldx = c->x; c->x = m->mx + ev->x; @@ -644,6 +1345,7 @@ configurerequest(XEvent *e) c->oldy = c->y; c->y = m->my + ev->y; } + #endif // STEAM_PATCH if (ev->value_mask & CWWidth) { c->oldw = c->w; c->w = ev->width; @@ -653,18 +1355,31 @@ configurerequest(XEvent *e) 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 */ + 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); + #if AUTORESIZE_PATCH + else + c->needresize = 1; + #endif // AUTORESIZE_PATCH } else configure(c); } else { wc.x = ev->x; wc.y = ev->y; + #if BAR_ANYBAR_PATCH + m = wintomon(ev->window); + for (bar = m->bar; bar; bar = bar->next) { + if (bar->win == ev->window) { + wc.y = bar->by; + wc.x = bar->bx; + } + } + #endif // BAR_ANYBAR_PATCH wc.width = ev->width; wc.height = ev->height; wc.border_width = ev->border_width; @@ -678,92 +1393,212 @@ configurerequest(XEvent *e) Monitor * createmon(void) { - Monitor *m; - unsigned int i; + Monitor *m, *mon; + int i, n, mi, max_bars = 2, istopbar = topbar; + #if MONITOR_RULES_PATCH + int layout; + #endif // MONITOR_RULES_PATCH + + const BarRule *br; + Bar *bar; + #if MONITOR_RULES_PATCH + int j; + const MonitorRule *mr; + #endif // MONITOR_RULES_PATCH m = ecalloc(1, sizeof(Monitor)); + #if EMPTYVIEW_PATCH + m->tagset[0] = m->tagset[1] = 0; + #else m->tagset[0] = m->tagset[1] = 1; + #endif // EMPTYVIEW_PATCH m->mfact = mfact; m->nmaster = nmaster; - m->rmaster = rmaster; + #if FLEXTILE_DELUXE_LAYOUT + m->nstack = nstack; + #endif // FLEXTILE_DELUXE_LAYOUT m->showbar = showbar; - m->topbar = topbar; + #if SETBORDERPX_PATCH + m->borderpx = borderpx; + #endif // SETBORDERPX_PATCH + #if VANITYGAPS_PATCH + m->gappih = gappih; + m->gappiv = gappiv; + m->gappoh = gappoh; + m->gappov = gappov; + #endif // VANITYGAPS_PATCH + for (mi = 0, mon = mons; mon; mon = mon->next, mi++); // monitor index + m->index = mi; + #if MONITOR_RULES_PATCH + for (j = 0; j < LENGTH(monrules); j++) { + mr = &monrules[j]; + if ((mr->monitor == -1 || mr->monitor == mi) + #if PERTAG_PATCH + && (mr->tag <= 0 || (m->tagset[0] & (1 << (mr->tag - 1)))) + #endif // PERTAG_PATCH + ) { + layout = MAX(mr->layout, 0); + layout = MIN(layout, LENGTH(layouts) - 1); + m->lt[0] = &layouts[layout]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[layout].symbol, sizeof m->ltsymbol); + + if (mr->mfact > -1) + m->mfact = mr->mfact; + if (mr->nmaster > -1) + m->nmaster = mr->nmaster; + if (mr->showbar > -1) + m->showbar = mr->showbar; + if (mr->topbar > -1) + istopbar = mr->topbar; + break; + } + } + #else 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)); + #endif // MONITOR_RULES_PATCH + + /* Derive the number of bars for this monitor based on bar rules */ + for (n = -1, i = 0; i < LENGTH(barrules); i++) { + br = &barrules[i]; + if (br->monitor == 'A' || br->monitor == -1 || br->monitor == mi) + n = MAX(br->bar, n); + } + + for (i = 0; i <= n && i < max_bars; i++) { + bar = ecalloc(1, sizeof(Bar)); + bar->mon = m; + bar->idx = i; + bar->next = m->bar; + bar->topbar = istopbar; + m->bar = bar; + istopbar = !istopbar; + bar->showbar = 1; + bar->external = 0; + #if BAR_BORDER_PATCH + bar->borderpx = borderpx; + #else + bar->borderpx = 0; + #endif // BAR_BORDER_PATCH + bar->bh = bh + bar->borderpx * 2; + bar->borderscheme = SchemeNorm; + } + + #if FLEXTILE_DELUXE_LAYOUT + m->ltaxis[LAYOUT] = m->lt[0]->preset.layout; + m->ltaxis[MASTER] = m->lt[0]->preset.masteraxis; + m->ltaxis[STACK] = m->lt[0]->preset.stack1axis; + m->ltaxis[STACK2] = m->lt[0]->preset.stack2axis; + #endif // FLEXTILE_DELUXE_LAYOUT + + #if PERTAG_PATCH + if (!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag)))) + die("fatal: could not malloc() %u bytes\n", sizeof(Pertag)); m->pertag->curtag = m->pertag->prevtag = 1; + for (i = 0; i <= NUMTAGS; i++) { + #if FLEXTILE_DELUXE_LAYOUT + m->pertag->nstacks[i] = m->nstack; + #endif // FLEXTILE_DELUXE_LAYOUT - for (i = 0; i <= LENGTH(tags); i++) { + #if !MONITOR_RULES_PATCH + /* init nmaster */ m->pertag->nmasters[i] = m->nmaster; + + /* init mfacts */ m->pertag->mfacts[i] = m->mfact; + #if PERTAGBAR_PATCH + /* init showbar */ + m->pertag->showbars[i] = m->showbar; + #endif // PERTAGBAR_PATCH + #endif // MONITOR_RULES_PATCH + + #if ZOOMSWAP_PATCH + m->pertag->prevzooms[i] = NULL; + #endif // ZOOMSWAP_PATCH + + /* init layouts */ + #if MONITOR_RULES_PATCH + for (j = 0; j < LENGTH(monrules); j++) { + mr = &monrules[j]; + if ((mr->monitor == -1 || mr->monitor == mi) && (mr->tag == -1 || mr->tag == i)) { + layout = MAX(mr->layout, 0); + layout = MIN(layout, LENGTH(layouts) - 1); + m->pertag->ltidxs[i][0] = &layouts[layout]; + m->pertag->ltidxs[i][1] = m->lt[0]; + m->pertag->nmasters[i] = (mr->nmaster > -1 ? mr->nmaster : m->nmaster); + m->pertag->mfacts[i] = (mr->mfact > -1 ? mr->mfact : m->mfact); + #if PERTAGBAR_PATCH + m->pertag->showbars[i] = (mr->showbar > -1 ? mr->showbar : m->showbar); + #endif // PERTAGBAR_PATCH + #if FLEXTILE_DELUXE_LAYOUT + m->pertag->ltaxis[i][LAYOUT] = m->pertag->ltidxs[i][0]->preset.layout; + m->pertag->ltaxis[i][MASTER] = m->pertag->ltidxs[i][0]->preset.masteraxis; + m->pertag->ltaxis[i][STACK] = m->pertag->ltidxs[i][0]->preset.stack1axis; + m->pertag->ltaxis[i][STACK2] = m->pertag->ltidxs[i][0]->preset.stack2axis; + #endif // FLEXTILE_DELUXE_LAYOUT + break; + } + } + #else m->pertag->ltidxs[i][0] = m->lt[0]; m->pertag->ltidxs[i][1] = m->lt[1]; + #if FLEXTILE_DELUXE_LAYOUT + /* init flextile axes */ + m->pertag->ltaxis[i][LAYOUT] = m->ltaxis[LAYOUT]; + m->pertag->ltaxis[i][MASTER] = m->ltaxis[MASTER]; + m->pertag->ltaxis[i][STACK] = m->ltaxis[STACK]; + m->pertag->ltaxis[i][STACK2] = m->ltaxis[STACK2]; + #endif // FLEXTILE_DELUXE_LAYOUT + #endif // MONITOR_RULES_PATCH m->pertag->sellts[i] = m->sellt; - m->pertag->showbars[i] = m->showbar; + #if VANITYGAPS_PATCH + m->pertag->enablegaps[i] = 1; + #endif // VANITYGAPS_PATCH } - + #endif // PERTAG_PATCH + #if INSETS_PATCH + m->inset = default_inset; + #endif // INSETS_PATCH return m; } -void -cyclelayout(const Arg *arg) { - Layout *l; - for(l = (Layout *)layouts; l != selmon->lt[selmon->sellt]; l++); - if(arg->i > 0) { - if(l->symbol && (l + 1)->symbol) - setlayout(&((Arg) { .v = (l + 1) })); - else - setlayout(&((Arg) { .v = layouts })); - } else { - if(l != layouts && (l - 1)->symbol) - setlayout(&((Arg) { .v = (l - 1) })); - else - setlayout(&((Arg) { .v = &layouts[LENGTH(layouts) - 2] })); - } -} - -void -deck(Monitor *m) { - unsigned int i, n, h, mw, my; - float mfacts = 0; - Client *c; - - for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { - if (n < m->nmaster) - mfacts += c->cfact; - } - if(n == 0) - return; - - if(n > m->nmaster) { - mw = m->nmaster ? m->ww * m->mfact : 0; - snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n - m->nmaster); - } - else - mw = m->ww; - for(i = my = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) - if(i < m->nmaster) { - h = (m->wh - my) * (c->cfact / mfacts); - resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False); - if (my + HEIGHT(c) < m->wh) - my += HEIGHT(c); - mfacts -= c->cfact; - } - else - resize(c, m->wx + mw, m->wy, m->ww - mw - (2*c->bw), m->wh - (2*c->bw), False); -} - void destroynotify(XEvent *e) { Client *c; + #if BAR_ANYBAR_PATCH + Monitor *m; + Bar *bar; + #endif // BAR_ANYBAR_PATCH XDestroyWindowEvent *ev = &e->xdestroywindow; if ((c = wintoclient(ev->window))) unmanage(c, 1); + #if SWALLOW_PATCH + else if ((c = swallowingclient(ev->window))) + unmanage(c->swallowing, 1); + #endif // SWALLOW_PATCH + #if BAR_SYSTRAY_PATCH + else if (showsystray && (c = wintosystrayicon(ev->window))) { + removesystrayicon(c); + drawbarwin(systray->bar); + } + #endif // BAR_SYSTRAY_PATCH + #if BAR_ANYBAR_PATCH + else { + m = wintomon(ev->window); + for (bar = m->bar; bar; bar = bar->next) { + if (bar->win == ev->window) { + unmanagealtbar(ev->window); + break; + } + } + } + #endif // BAR_ANYBAR_PATCH } void @@ -807,87 +1642,148 @@ dirtomon(int dir) void drawbar(Monitor *m) { - int x, w; - int boxs = drw->fonts->h / 9; - int boxw = drw->fonts->h / 6 + 2; - unsigned int i, occ = 0, urg = 0; - Client *c; - - /* draw status first so it can be overdrawn by tags later */ - if (m == selmon) { /* status is only drawn on selected monitor */ - char *ts = stextc; - char *tp = stextc; - char ctmp; - - drw_setscheme(drw, scheme[SchemeStatus]); - x = drw_text(drw, m->ww - wstext -2 * sp, 0, lrpad / 2, bh, 0, "", 0); /* to keep left padding clean */ - for (;;) { - if ((unsigned char)*ts > LENGTH(colors) + 10) { - ts++; - continue; - } - ctmp = *ts; - *ts = '\0'; - if (*tp != '\0') - x = drw_text(drw, x, 0, TTEXTW(tp), bh, 0, tp, 0); - if (ctmp == '\0') - break; - /* - 11 to compensate for + 10 above */ - drw_setscheme(drw, scheme[(unsigned char)ctmp - 11]); - *ts = ctmp; - tp = ++ts; - } - drw_setscheme(drw, scheme[SchemeNorm]); - drw_text(drw, x, 0, m->ww - x, bh, 0, "", 0); /* to keep right padding clean */ - } - - for (c = m->clients; c; c = c->next) { - occ |= c->tags; - if (c->isurgent) - 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 ? 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, - m == selmon && selmon->sel && selmon->sel->tags & 1 << i, - urg & 1 << i); - x += w; - } - w = blw = TEXTW(m->ltsymbol); - drw_setscheme(drw, scheme[SchemeTagsNorm]); - x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); - - if ((w = m->ww - wstext - x) > bh) { - if (m->sel) { - 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) - drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); - } else { - 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); + Bar *bar; + for (bar = m->bar; bar; bar = bar->next) + drawbarwin(bar); } void drawbars(void) { Monitor *m; - for (m = mons; m; m = m->next) drawbar(m); } +void +drawbarwin(Bar *bar) +{ + if (!bar || !bar->win || bar->external) + return; + int r, w, total_drawn = 0; + int rx, lx, rw, lw; // bar size, split between left and right if a center module is added + const BarRule *br; + + if (bar->borderpx) { + XSetForeground(drw->dpy, drw->gc, scheme[bar->borderscheme][ColBorder].pixel); + XFillRectangle(drw->dpy, drw->drawable, drw->gc, 0, 0, bar->bw, bar->bh); + } + + BarArg warg = { 0 }; + BarArg darg = { 0 }; + warg.h = bar->bh - 2 * bar->borderpx; + + rw = lw = bar->bw - 2 * bar->borderpx; + rx = lx = bar->borderpx; + + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, lx, bar->borderpx, lw, bar->bh - 2 * bar->borderpx, 1, 1); + for (r = 0; r < LENGTH(barrules); r++) { + br = &barrules[r]; + if (br->bar != bar->idx || !br->widthfunc || (br->monitor == 'A' && bar->mon != selmon)) + continue; + if (br->monitor != 'A' && br->monitor != -1 && br->monitor != bar->mon->index) + continue; + drw_setscheme(drw, scheme[SchemeNorm]); + warg.w = (br->alignment < BAR_ALIGN_RIGHT_LEFT ? lw : rw); + + w = br->widthfunc(bar, &warg); + w = MIN(warg.w, w); + + if (lw <= 0) { // if left is exhausted then switch to right side, and vice versa + lw = rw; + lx = rx; + } else if (rw <= 0) { + rw = lw; + rx = lx; + } + + switch(br->alignment) { + default: + case BAR_ALIGN_NONE: + case BAR_ALIGN_LEFT_LEFT: + case BAR_ALIGN_LEFT: + bar->x[r] = lx; + if (lx == rx) { + rx += w; + rw -= w; + } + lx += w; + lw -= w; + break; + case BAR_ALIGN_LEFT_RIGHT: + case BAR_ALIGN_RIGHT: + bar->x[r] = lx + lw - w; + if (lx == rx) + rw -= w; + lw -= w; + break; + case BAR_ALIGN_LEFT_CENTER: + case BAR_ALIGN_CENTER: + bar->x[r] = lx + lw / 2 - w / 2; + if (lx == rx) { + rw = rx + rw - bar->x[r] - w; + rx = bar->x[r] + w; + } + lw = bar->x[r] - lx; + break; + case BAR_ALIGN_RIGHT_LEFT: + bar->x[r] = rx; + if (lx == rx) { + lx += w; + lw -= w; + } + rx += w; + rw -= w; + break; + case BAR_ALIGN_RIGHT_RIGHT: + bar->x[r] = rx + rw - w; + if (lx == rx) + lw -= w; + rw -= w; + break; + case BAR_ALIGN_RIGHT_CENTER: + bar->x[r] = rx + rw / 2 - w / 2; + if (lx == rx) { + lw = lx + lw - bar->x[r] + w; + lx = bar->x[r] + w; + } + rw = bar->x[r] - rx; + break; + } + bar->w[r] = w; + darg.x = bar->x[r]; + darg.y = bar->borderpx; + darg.h = bar->bh - 2 * bar->borderpx; + darg.w = bar->w[r]; + if (br->drawfunc) + total_drawn += br->drawfunc(bar, &darg); + } + + if (total_drawn == 0 && bar->showbar) { + bar->showbar = 0; + updatebarpos(bar->mon); + XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh); + arrange(bar->mon); + } + else if (total_drawn > 0 && !bar->showbar) { + bar->showbar = 1; + updatebarpos(bar->mon); + XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh); + drw_map(drw, bar->win, 0, 0, bar->bw, bar->bh); + arrange(bar->mon); + } else + drw_map(drw, bar->win, 0, 0, bar->bw, bar->bh); +} + +#if !FOCUSONCLICK_PATCH void enternotify(XEvent *e) { Client *c; + #if LOSEFULLSCREEN_PATCH + Client *sel; + #endif // LOSEFULLSCREEN_PATCH Monitor *m; XCrossingEvent *ev = &e->xcrossing; @@ -896,12 +1792,19 @@ enternotify(XEvent *e) c = wintoclient(ev->window); m = c ? c->mon : wintomon(ev->window); if (m != selmon) { - unfocus(selmon->sel, 1); + #if LOSEFULLSCREEN_PATCH + sel = selmon->sel; + selmon = m; + unfocus(sel, 1, c); + #else + unfocus(selmon->sel, 1, c); selmon = m; + #endif // LOSEFULLSCREEN_PATCH } else if (!c || c == selmon->sel) return; focus(c); } +#endif // FOCUSONCLICK_PATCH void expose(XEvent *e) @@ -919,7 +1822,7 @@ focus(Client *c) if (!c || !ISVISIBLE(c)) for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext); if (selmon->sel && selmon->sel != c) - unfocus(selmon->sel, 0); + unfocus(selmon->sel, 0, c); if (c) { if (c->mon != selmon) selmon = c->mon; @@ -928,7 +1831,12 @@ focus(Client *c) detachstack(c); attachstack(c); grabbuttons(c, 1); - XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); + #if !BAR_FLEXWINTITLE_PATCH + if (c->isfloating) + XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColFloat].pixel); + else + XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); + #endif // BAR_FLEXWINTITLE_PATCH setfocus(c); } else { XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); @@ -936,6 +1844,13 @@ focus(Client *c) } selmon->sel = c; drawbars(); + + #if ON_EMPTY_KEYS_PATCH + if ((isempty && selmon->sel) || (!isempty && !selmon->sel)) { + isempty = !isempty; + grabkeys(); + } + #endif // ON_EMPTY_KEYS_PATCH } /* there are some broken focus acquiring clients needing extra handling */ @@ -952,16 +1867,29 @@ void focusmon(const Arg *arg) { Monitor *m; + #if LOSEFULLSCREEN_PATCH + Client *sel; + #endif // LOSEFULLSCREEN_PATCH if (!mons->next) return; if ((m = dirtomon(arg->i)) == selmon) return; - unfocus(selmon->sel, 0); + #if LOSEFULLSCREEN_PATCH + sel = selmon->sel; selmon = m; + unfocus(sel, 0, NULL); + #else + unfocus(selmon->sel, 0, NULL); + selmon = m; + #endif // LOSEFULLSCREEN_PATCH focus(NULL); + #if WARP_PATCH + warp(selmon->sel); + #endif // WARP_PATCH } +#if !STACKER_PATCH void focusstack(const Arg *arg) { @@ -969,6 +1897,25 @@ focusstack(const Arg *arg) if (!selmon->sel) return; + #if ALWAYSFULLSCREEN_PATCH + if (selmon->sel->isfullscreen) + return; + #endif // ALWAYSFULLSCREEN_PATCH + #if BAR_WINTITLEACTIONS_PATCH + if (arg->i > 0) { + for (c = selmon->sel->next; c && (!ISVISIBLE(c) || (arg->i == 1 && HIDDEN(c))); c = c->next); + if (!c) + for (c = selmon->clients; c && (!ISVISIBLE(c) || (arg->i == 1 && HIDDEN(c))); c = c->next); + } else { + for (i = selmon->clients; i != selmon->sel; i = i->next) + if (ISVISIBLE(i) && !(arg->i == -1 && HIDDEN(i))) + c = i; + if (!c) + for (; i; i = i->next) + if (ISVISIBLE(i) && !(arg->i == -1 && HIDDEN(i))) + c = i; + } + #else if (arg->i > 0) { for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); if (!c) @@ -982,11 +1929,13 @@ focusstack(const Arg *arg) if (ISVISIBLE(i)) c = i; } + #endif // BAR_WINTITLEACTIONS_PATCH if (c) { focus(c); restack(selmon); } } +#endif // STACKER_PATCH Atom getatomprop(Client *c, Atom prop) @@ -996,11 +1945,27 @@ getatomprop(Client *c, Atom prop) unsigned char *p = NULL; Atom da, atom = None; + #if BAR_SYSTRAY_PATCH + /* FIXME getatomprop should return the number of items and a pointer to + * the stored data instead of this workaround */ + Atom req = XA_ATOM; + if (prop == xatom[XembedInfo]) + req = xatom[XembedInfo]; + + if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, + &da, &di, &dl, &dl, &p) == Success && p) { + atom = *(Atom *)p; + if (da == xatom[XembedInfo] && dl == 2) + atom = ((Atom *)p)[1]; + XFree(p); + } + #else if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, &da, &di, &dl, &dl, &p) == Success && p) { atom = *(Atom *)p; XFree(p); } + #endif // BAR_SYSTRAY_PATCH return atom; } @@ -1069,7 +2034,11 @@ grabbuttons(Client *c, int 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) + if (buttons[i].click == ClkClientWin + #if NO_MOD_BUTTONS_PATCH + && (nomodbuttons || buttons[i].mask != 0) + #endif // NO_MOD_BUTTONS_PATCH + ) for (j = 0; j < LENGTH(modifiers); j++) XGrabButton(dpy, buttons[i].button, buttons[i].mask | modifiers[j], @@ -1079,7 +2048,11 @@ grabbuttons(Client *c, int focused) } void +#if KEYMODES_PATCH +grabdefkeys(void) +#else grabkeys(void) +#endif // KEYMODES_PATCH { updatenumlockmask(); { @@ -1093,13 +2066,25 @@ grabkeys(void) for (j = 0; j < LENGTH(modifiers); j++) XGrabKey(dpy, code, keys[i].mod | modifiers[j], root, True, GrabModeAsync, GrabModeAsync); + #if ON_EMPTY_KEYS_PATCH + if (!selmon->sel) + for (i = 0; i < LENGTH(on_empty_keys); i++) + if ((code = XKeysymToKeycode(dpy, on_empty_keys[i].keysym))) + for (j = 0; j < LENGTH(modifiers); j++) + XGrabKey(dpy, code, on_empty_keys[i].mod | modifiers[j], root, + True, GrabModeAsync, GrabModeAsync); + #endif // ON_EMPTY_KEYS_PATCH } } void incnmaster(const Arg *arg) { + #if PERTAG_PATCH selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); + #else + selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + #endif // PERTAG_PATCH arrange(selmon); } @@ -1116,27 +2101,50 @@ isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) #endif /* XINERAMA */ void +#if KEYMODES_PATCH +keydefpress(XEvent *e) +#else keypress(XEvent *e) +#endif // KEYMODES_PATCH { unsigned int i; - KeySym keysym; + int keysyms_return; + KeySym* keysym; XKeyEvent *ev; ev = &e->xkey; - keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); + keysym = XGetKeyboardMapping(dpy, (KeyCode)ev->keycode, 1, &keysyms_return); for (i = 0; i < LENGTH(keys); i++) - if (keysym == keys[i].keysym - && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) - && keys[i].func) + if (*keysym == keys[i].keysym + && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) + && keys[i].func) keys[i].func(&(keys[i].arg)); + #if ON_EMPTY_KEYS_PATCH + if (!selmon->sel) + for (i = 0; i < LENGTH(on_empty_keys); i++) + if (*keysym == on_empty_keys[i].keysym + && CLEANMASK(on_empty_keys[i].mod) == CLEANMASK(ev->state) + && on_empty_keys[i].func) + on_empty_keys[i].func(&(on_empty_keys[i].arg)); + #endif // ON_EMPTY_KEYS_PATCH + XFree(keysym); } void killclient(const Arg *arg) { + #if ISPERMANENT_PATCH + if (!selmon->sel || selmon->sel->ispermanent) + #else if (!selmon->sel) + #endif // ISPERMANENT_PATCH return; - if (!sendevent(selmon->sel, wmatom[WMDelete])) { + #if BAR_SYSTRAY_PATCH + if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0, 0, 0)) + #else + if (!sendevent(selmon->sel, wmatom[WMDelete])) + #endif // BAR_SYSTRAY_PATCH + { XGrabServer(dpy); XSetErrorHandler(xerrordummy); XSetCloseDownMode(dpy, DestroyAll); @@ -1144,33 +2152,77 @@ killclient(const Arg *arg) XSync(dpy, False); XSetErrorHandler(xerror); XUngrabServer(dpy); + #if WARP_PATCH + force_warp = 1; + #endif // WARP_PATCH } + #if SWAPFOCUS_PATCH && PERTAG_PATCH + selmon->pertag->prevclient[selmon->pertag->curtag] = NULL; + #endif // SWAPFOCUS_PATCH } void manage(Window w, XWindowAttributes *wa) { Client *c, *t = NULL; + #if SWALLOW_PATCH + Client *term = NULL; + #endif // SWALLOW_PATCH Window trans = None; XWindowChanges wc; c = ecalloc(1, sizeof(Client)); c->win = w; + #if SWALLOW_PATCH + c->pid = winpid(w); + #endif // SWALLOW_PATCH /* 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; + #if CFACTS_PATCH c->cfact = 1.0; - + #endif // CFACTS_PATCH updatetitle(c); if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { c->mon = t->mon; c->tags = t->tags; + #if SETBORDERPX_PATCH + c->bw = c->mon->borderpx; + #else + c->bw = borderpx; + #endif // SETBORDERPX_PATCH + #if CENTER_TRANSIENT_WINDOWS_BY_PARENT_PATCH + c->x = t->x + WIDTH(t) / 2 - WIDTH(c) / 2; + c->y = t->y + HEIGHT(t) / 2 - HEIGHT(c) / 2; + #elif CENTER_PATCH && CENTER_TRANSIENT_WINDOWS_PATCH + c->iscentered = 1; + #elif CENTER_TRANSIENT_WINDOWS_PATCH + c->x = c->mon->wx + (c->mon->ww - WIDTH(c)) / 2; + c->y = c->mon->wy + (c->mon->wh - HEIGHT(c)) / 2; + #elif CENTER_PATCH + if (c->x == c->mon->wx && c->y == c->mon->wy) + c->iscentered = 1; + #endif // CENTER_TRANSIENT_WINDOWS_PATCH | CENTER_TRANSIENT_WINDOWS_BY_PARENT_PATCH | CENTER_PATCH } else { c->mon = selmon; + #if CENTER_PATCH + if (c->x == c->mon->wx && c->y == c->mon->wy) + c->iscentered = 1; + #endif // CENTER_PATCH + #if SETBORDERPX_PATCH + c->bw = c->mon->borderpx; + #else + c->bw = borderpx; + #endif // SETBORDERPX_PATCH applyrules(c); + #if SWALLOW_PATCH + term = termforwin(c); + if (term) + c->mon = term->mon; + #endif // SWALLOW_PATCH } if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw) @@ -1179,39 +2231,122 @@ manage(Window w, XWindowAttributes *wa) c->y = c->mon->my + c->mon->mh - HEIGHT(c); c->x = MAX(c->x, c->mon->mx); /* 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->y = MAX(c->y, ((c->mon->bar->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; wc.border_width = c->bw; XConfigureWindow(dpy, w, CWBorderWidth, &wc); - XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel); + #if !BAR_FLEXWINTITLE_PATCH + if (c->isfloating) + XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColFloat].pixel); + else + XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel); + #endif // BAR_FLEXWINTITLE_PATCH configure(c); /* propagates border_width, if size doesn't change */ - updatewindowtype(c); + #if !FLOATPOS_PATCH updatesizehints(c); + #endif // FLOATPOS_PATCH + if (getatomprop(c, netatom[NetWMState]) == netatom[NetWMFullscreen]) + setfullscreen(c, 1); updatewmhints(c); - c->x = c->mon->mx + (c->mon->mw - WIDTH(c)) / 2; - c->y = c->mon->my + (c->mon->mh - HEIGHT(c)) / 2; + #if DECORATION_HINTS_PATCH + updatemotifhints(c); + #endif // DECORATION_HINTS_PATCH + #if CENTER_PATCH + if (c->iscentered) { + c->x = c->mon->wx + (c->mon->ww - WIDTH(c)) / 2; + c->y = c->mon->wy + (c->mon->wh - HEIGHT(c)) / 2; + } + #endif // CENTER_PATCH + #if SAVEFLOATS_PATCH || EXRESIZE_PATCH + c->sfx = -9999; + c->sfy = -9999; + c->sfw = c->w; + c->sfh = c->h; + #endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH + XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); grabbuttons(c, 0); + #if MAXIMIZE_PATCH + c->wasfloating = 0; + c->ismax = 0; + #elif EXRESIZE_PATCH + c->wasfloating = 0; + #endif // MAXIMIZE_PATCH / EXRESIZE_PATCH + if (!c->isfloating) c->isfloating = c->oldstate = trans != None || c->isfixed; - if (c->isfloating) + if (c->isfloating) { XRaiseWindow(dpy, c->win); + XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColFloat].pixel); + } + #if ATTACHABOVE_PATCH || ATTACHASIDE_PATCH || ATTACHBELOW_PATCH || ATTACHBOTTOM_PATCH + attachx(c); + #else attach(c); + #endif attachstack(c); XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, (unsigned char *) &(c->win), 1); + #if NET_CLIENT_LIST_STACKING_PATCH XChangeProperty(dpy, root, netatom[NetClientListStacking], XA_WINDOW, 32, PropModePrepend, (unsigned char *) &(c->win), 1); + #endif // NET_CLIENT_LIST_STACKING_PATCH XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ + + #if BAR_WINTITLEACTIONS_PATCH + if (!HIDDEN(c)) + setclientstate(c, NormalState); + #else setclientstate(c, NormalState); + #endif // BAR_WINTITLEACTIONS_PATCH if (c->mon == selmon) - unfocus(selmon->sel, 0); + unfocus(selmon->sel, 0, c); c->mon->sel = c; + #if SWALLOW_PATCH + if (!(term && swallow(term, c))) { + #if RIODRAW_PATCH + if (riopid && (!riodraw_matchpid || isdescprocess(riopid, c->pid))) { + if (riodimensions[3] != -1) + rioposition(c, riodimensions[0], riodimensions[1], riodimensions[2], riodimensions[3]); + else { + killclient(&((Arg) { .v = c })); + return; + } + } + #endif // RIODRAW_PATCH + arrange(c->mon); + #if BAR_WINTITLEACTIONS_PATCH + if (!HIDDEN(c)) + XMapWindow(dpy, c->win); + #else + XMapWindow(dpy, c->win); + #endif // BAR_WINTITLEACTIONS_PATCH + } + #else + #if RIODRAW_PATCH + if (riopid) { + if (riodimensions[3] != -1) + rioposition(c, riodimensions[0], riodimensions[1], riodimensions[2], riodimensions[3]); + else { + killclient(&((Arg) { .v = c })); + return; + } + } + #endif // RIODRAW_PATCH arrange(c->mon); + #if BAR_WINTITLEACTIONS_PATCH + if (!HIDDEN(c)) + XMapWindow(dpy, c->win); + #else XMapWindow(dpy, c->win); + #endif // BAR_WINTITLEACTIONS_PATCH + #endif // SWALLOW_PATCH focus(NULL); + + #if BAR_EWMHTAGS_PATCH + setfloatinghint(c); + #endif // BAR_EWMHTAGS_PATCH } void @@ -1230,48 +2365,54 @@ maprequest(XEvent *e) static XWindowAttributes wa; XMapRequestEvent *ev = &e->xmaprequest; + #if BAR_SYSTRAY_PATCH + Client *i; + if (showsystray && systray && (i = wintosystrayicon(ev->window))) { + sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); + drawbarwin(systray->bar); + } + #endif // BAR_SYSTRAY_PATCH + if (!XGetWindowAttributes(dpy, ev->window, &wa)) return; if (wa.override_redirect) return; + #if BAR_ANYBAR_PATCH + if (wmclasscontains(ev->window, altbarclass, "")) + managealtbar(ev->window, &wa); + else + #endif // BAR_ANYBAR_PATCH if (!wintoclient(ev->window)) manage(ev->window, &wa); } -void -monocle(Monitor *m) -{ - unsigned int n = 0; - Client *c; - - 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); -} - +#if !FOCUSONCLICK_PATCH void motionnotify(XEvent *e) { static Monitor *mon = NULL; Monitor *m; + #if LOSEFULLSCREEN_PATCH + Client *sel; + #endif // LOSEFULLSCREEN_PATCH XMotionEvent *ev = &e->xmotion; - if (ev->window != root) { - if (ev->window == selmon->barwin) - updatebarcursor(ev->x); + if (ev->window != root) return; - } if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { - unfocus(selmon->sel, 1); + #if LOSEFULLSCREEN_PATCH + sel = selmon->sel; + selmon = m; + unfocus(sel, 1, NULL); + #else + unfocus(selmon->sel, 1, NULL); selmon = m; + #endif // LOSEFULLSCREEN_PATCH focus(NULL); } mon = m; } +#endif // FOCUSONCLICK_PATCH void movemouse(const Arg *arg) @@ -1284,8 +2425,15 @@ movemouse(const Arg *arg) if (!(c = selmon->sel)) return; + #if !FAKEFULLSCREEN_PATCH + #if FAKEFULLSCREEN_CLIENT_PATCH + if (c->isfullscreen && c->fakefullscreen != 1) /* no support moving fullscreen windows by mouse */ + return; + #else if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ return; + #endif // FAKEFULLSCREEN_CLIENT_PATCH + #endif // FAKEFULLSCREEN_PATCH restack(selmon); ocx = c->x; ocy = c->y; @@ -1294,6 +2442,7 @@ movemouse(const Arg *arg) return; if (!getrootptr(&x, &y)) return; + ignoreconfigurerequests = 1; do { XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); switch(ev.type) { @@ -1318,28 +2467,58 @@ movemouse(const Arg *arg) 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)) + && (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) { + #if SAVEFLOATS_PATCH || EXRESIZE_PATCH + c->sfx = -9999; // disable savefloats when using movemouse + #endif // SAVEFLOATS_PATCH | EXRESIZE_PATCH togglefloating(NULL); - if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) + } + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) { + #if SAVEFLOATS_PATCH || EXRESIZE_PATCH resize(c, nx, ny, c->w, c->h, 1); + /* save last known float coordinates */ + c->sfx = nx; + c->sfy = ny; + #else + resize(c, nx, ny, c->w, c->h, 1); + #endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH + } + #if ROUNDED_CORNERS_PATCH + drawroundedcorners(c); + #endif // ROUNDED_CORNERS_PATCH break; } } while (ev.type != ButtonRelease); XUngrabPointer(dpy, CurrentTime); if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { + #if SCRATCHPADS_PATCH + if (c->tags & SPTAGMASK) { + c->mon->tagset[c->mon->seltags] ^= (c->tags & SPTAGMASK); + m->tagset[m->seltags] |= (c->tags & SPTAGMASK); + } + #endif // SCRATCHPADS_PATCH sendmon(c, m); selmon = m; focus(NULL); } + #if ROUNDED_CORNERS_PATCH + drawroundedcorners(c); + #endif // ROUNDED_CORNERS_PATCH + ignoreconfigurerequests = 0; } Client * nexttiled(Client *c) { + #if BAR_WINTITLEACTIONS_PATCH + for (; c && (c->isfloating || !ISVISIBLE(c) || HIDDEN(c)); c = c->next); + #else for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); + #endif // BAR_WINTITLEACTIONS_PATCH return c; } +#if !ZOOMSWAP_PATCH || TAGINTOSTACK_ALLMASTER_PATCH || TAGINTOSTACK_ONEMASTER_PATCH void pop(Client *c) { @@ -1348,6 +2527,7 @@ pop(Client *c) focus(c); arrange(c->mon); } +#endif // !ZOOMSWAP_PATCH / TAGINTOSTACK_ALLMASTER_PATCH / TAGINTOSTACK_ONEMASTER_PATCH void propertynotify(XEvent *e) @@ -1356,11 +2536,28 @@ propertynotify(XEvent *e) Window trans; XPropertyEvent *ev = &e->xproperty; - if ((ev->window == root) && (ev->atom == XA_WM_NAME)) + #if BAR_SYSTRAY_PATCH + if (showsystray && (c = wintosystrayicon(ev->window))) { + if (ev->atom == XA_WM_NORMAL_HINTS) { + updatesizehints(c); + updatesystrayicongeom(c, c->w, c->h); + } + else + updatesystrayiconstate(c, ev); + drawbarwin(systray->bar); + } + #endif // BAR_SYSTRAY_PATCH + + if ((ev->window == root) && (ev->atom == XA_WM_NAME)) { + #if DWMC_PATCH || FSIGNAL_PATCH + if (!fake_signal()) + updatestatus(); + #else updatestatus(); - else if (ev->state == PropertyDelete) + #endif // DWMC_PATCH / FSIGNAL_PATCH + } else if (ev->state == PropertyDelete) { return; /* ignore */ - else if ((c = wintoclient(ev->window))) { + } else if ((c = wintoclient(ev->window))) { switch(ev->atom) { default: break; case XA_WM_TRANSIENT_FOR: @@ -1373,7 +2570,8 @@ propertynotify(XEvent *e) break; case XA_WM_HINTS: updatewmhints(c); - drawbars(); + if (c->isurgent) + drawbars(); break; } if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { @@ -1381,15 +2579,58 @@ propertynotify(XEvent *e) if (c == c->mon->sel) drawbar(c->mon); } - if (ev->atom == netatom[NetWMWindowType]) - updatewindowtype(c); + #if DECORATION_HINTS_PATCH + if (ev->atom == motifatom) + updatemotifhints(c); + #endif // DECORATION_HINTS_PATCH } } void quit(const Arg *arg) { + #if COOL_AUTOSTART_PATCH + size_t i; + #endif // COOL_AUTOSTART_PATCH + #if ONLYQUITONEMPTY_PATCH + unsigned int n; + Window *junk = malloc(1); + + XQueryTree(dpy, root, junk, junk, &junk, &n); + + #if COOL_AUTOSTART_PATCH + if (n - autostart_len <= quit_empty_window_count) + #else + if (n <= quit_empty_window_count) + #endif // COOL_AUTOSTART_PATCH + { + #if RESTARTSIG_PATCH + if (arg->i) + restart = 1; + #endif // RESTARTSIG_PATCH + running = 0; + } + else + printf("[dwm] not exiting (n=%d)\n", n); + + free(junk); + #else + #if RESTARTSIG_PATCH + if (arg->i) + restart = 1; + #endif // RESTARTSIG_PATCH running = 0; + #endif // ONLYQUITONEMPTY_PATCH + + #if COOL_AUTOSTART_PATCH + /* kill child processes */ + for (i = 0; i < autostart_len; i++) { + if (0 < autostart_pids[i]) { + kill(autostart_pids[i], SIGTERM); + waitpid(autostart_pids[i], NULL, 0); + } + } + #endif // COOL_AUTOSTART_PATCH } Monitor * @@ -1417,45 +2658,71 @@ void resizeclient(Client *c, int x, int y, int w, int h) { XWindowChanges wc; - unsigned int n; - unsigned int gapoffset; - unsigned int gapincr; - Client *nbc; + 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; + #if EXRESIZE_PATCH + c->expandmask = 0; + #endif // EXRESIZE_PATCH wc.border_width = c->bw; - - /* Get number of clients for the selected monitor */ - for (n = 0, nbc = nexttiled(selmon->clients); nbc; nbc = nexttiled(nbc->next), n++); - - /* Do nothing if layout is floating */ - if (c->isfloating || selmon->lt[selmon->sellt]->arrange == NULL) { - gapincr = gapoffset = 0; - } else { - /* Remove border and gap if layout is monocle or only one client */ - if (selmon->lt[selmon->sellt]->arrange == monocle) { - gapoffset = gappx; - gapincr = 2 * gappx; - // wc.border_width = 0; - } else { - gapoffset = gappx; - gapincr = 2 * gappx; - } + #if NOBORDER_PATCH + if (((nexttiled(c->mon->clients) == c && !nexttiled(c->next)) + #if MONOCLE_LAYOUT + || &monocle == c->mon->lt[c->mon->sellt]->arrange + #endif // MONOCLE_LAYOUT + #if DECK_LAYOUT + || (&deck == c->mon->lt[c->mon->sellt]->arrange && + c->mon->nmaster == 0) + #endif // DECK_LAYOUT + #if FLEXTILE_DELUXE_LAYOUT + || (&flextile == c->mon->lt[c->mon->sellt]->arrange && ( + (c->mon->ltaxis[LAYOUT] == NO_SPLIT && + c->mon->ltaxis[MASTER] == MONOCLE) || + (c->mon->ltaxis[STACK] == MONOCLE && + c->mon->nmaster == 0))) + #endif //FLEXTILE_DELUXE_LAYOUT + ) + #if FAKEFULLSCREEN_CLIENT_PATCH + && (c->fakefullscreen == 1 || !c->isfullscreen) + #else + && !c->isfullscreen + #endif // FAKEFULLSCREEN_CLIENT_PATCH + && !c->isfloating + && c->mon->lt[c->mon->sellt]->arrange) { + wc.width += c->bw * 2; + wc.height += c->bw * 2; + wc.border_width = 0; } - - c->oldx = c->x; c->x = wc.x = x + gapoffset; - c->oldy = c->y; c->y = wc.y = y + gapoffset; - c->oldw = c->w; c->w = wc.width = w - gapincr; - c->oldh = c->h; c->h = wc.height = h - gapincr; - + #endif // NOBORDER_PATCH XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); configure(c); + #if FAKEFULLSCREEN_CLIENT_PATCH + if (c->fakefullscreen == 1) + /* Exception: if the client was in actual fullscreen and we exit out to fake fullscreen + * mode, then the focus would drift to whichever window is under the mouse cursor at the + * time. To avoid this we pass True to XSync which will make the X server disregard any + * other events in the queue thus cancelling the EnterNotify event that would otherwise + * have changed focus. */ + XSync(dpy, True); + else + XSync(dpy, False); + #else XSync(dpy, False); + #endif // FAKEFULLSCREEN_CLIENT_PATCH } void resizemouse(const Arg *arg) { int ocx, ocy, nw, nh; + #if RESIZEPOINT_PATCH || RESIZECORNERS_PATCH + int opx, opy, och, ocw, nx, ny; + int horizcorner, vertcorner; + unsigned int dui; + Window dummy; + #endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH Client *c; Monitor *m; XEvent ev; @@ -1463,15 +2730,45 @@ resizemouse(const Arg *arg) if (!(c = selmon->sel)) return; + #if !FAKEFULLSCREEN_PATCH + #if FAKEFULLSCREEN_CLIENT_PATCH + if (c->isfullscreen && c->fakefullscreen != 1) /* no support resizing fullscreen windows by mouse */ + return; + #else if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ return; + #endif // FAKEFULLSCREEN_CLIENT_PATCH + #endif // !FAKEFULLSCREEN_PATCH restack(selmon); ocx = c->x; ocy = c->y; + #if RESIZEPOINT_PATCH + och = c->h; + ocw = c->w; + #elif RESIZECORNERS_PATCH + och = c->y + c->h; + ocw = c->x + c->w; + #endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH + #if RESIZEPOINT_PATCH || RESIZECORNERS_PATCH + if (!XQueryPointer(dpy, c->win, &dummy, &dummy, &opx, &opy, &nx, &ny, &dui)) + return; + horizcorner = nx < c->w / 2; + vertcorner = ny < c->h / 2; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, + None, cursor[horizcorner | (vertcorner << 1)]->cursor, CurrentTime) != GrabSuccess) + return; + #if RESIZECORNERS_PATCH + XWarpPointer (dpy, None, c->win, 0, 0, 0, 0, + horizcorner ? (-c->bw) : (c->w + c->bw - 1), + vertcorner ? (-c->bw) : (c->h + c->bw - 1)); + #endif // RESIZECORNERS_PATCH + #else 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); + #endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH + ignoreconfigurerequests = 1; do { XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); switch(ev.type) { @@ -1485,28 +2782,80 @@ resizemouse(const Arg *arg) continue; lasttime = ev.xmotion.time; + #if RESIZEPOINT_PATCH + nx = horizcorner ? (ocx + ev.xmotion.x - opx) : c->x; + ny = vertcorner ? (ocy + ev.xmotion.y - opy) : c->y; + nw = MAX(horizcorner ? (ocx + ocw - nx) : (ocw + (ev.xmotion.x - opx)), 1); + nh = MAX(vertcorner ? (ocy + och - ny) : (och + (ev.xmotion.y - opy)), 1); + #elif RESIZECORNERS_PATCH + nx = horizcorner ? ev.xmotion.x : c->x; + ny = vertcorner ? ev.xmotion.y : c->y; + nw = MAX(horizcorner ? (ocw - nx) : (ev.xmotion.x - ocx - 2 * c->bw + 1), 1); + nh = MAX(vertcorner ? (och - ny) : (ev.xmotion.y - ocy - 2 * c->bw + 1), 1); + #else nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); + #endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH 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 (!c->isfloating && selmon->lt[selmon->sellt]->arrange - && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) + && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) { + #if SAVEFLOATS_PATCH || EXRESIZE_PATCH + c->sfx = -9999; // disable savefloats when using resizemouse + #endif // SAVEFLOATS_PATCH | EXRESIZE_PATCH togglefloating(NULL); + } } - if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) { + #if RESIZECORNERS_PATCH || RESIZEPOINT_PATCH + resizeclient(c, nx, ny, nw, nh); + #if SAVEFLOATS_PATCH || EXRESIZE_PATCH + /* save last known float dimensions */ + c->sfx = nx; + c->sfy = ny; + c->sfw = nw; + c->sfh = nh; + #endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH + #else resize(c, c->x, c->y, nw, nh, 1); + #if SAVEFLOATS_PATCH || EXRESIZE_PATCH + c->sfx = c->x; + c->sfy = c->y; + c->sfw = nw; + c->sfh = nh; + #endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH + #endif // RESIZECORNERS_PATCH + #if ROUNDED_CORNERS_PATCH + drawroundedcorners(c); + #endif // ROUNDED_CORNERS_PATCH + } break; } } while (ev.type != ButtonRelease); + #if !RESIZEPOINT_PATCH + #if RESIZECORNERS_PATCH + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, + horizcorner ? (-c->bw) : (c->w + c->bw - 1), + vertcorner ? (-c->bw) : (c->h + c->bw - 1)); + #else XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); + #endif // RESIZECORNERS_PATCH + #endif // RESIZEPOINT_PATCH XUngrabPointer(dpy, CurrentTime); while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { + #if SCRATCHPADS_PATCH + if (c->tags & SPTAGMASK) { + c->mon->tagset[c->mon->seltags] ^= (c->tags & SPTAGMASK); + m->tagset[m->seltags] |= (c->tags & SPTAGMASK); + } + #endif // SCRATCHPADS_PATCH sendmon(c, m); selmon = m; focus(NULL); } + ignoreconfigurerequests = 0; } void @@ -1515,6 +2864,9 @@ restack(Monitor *m) Client *c; XEvent ev; XWindowChanges wc; + #if WARP_PATCH && FLEXTILE_DELUXE_LAYOUT + int n; + #endif // WARP_PATCH drawbar(m); if (!m->sel) @@ -1523,7 +2875,7 @@ restack(Monitor *m) XRaiseWindow(dpy, m->sel->win); if (m->lt[m->sellt]->arrange) { wc.stack_mode = Below; - wc.sibling = m->barwin; + wc.sibling = m->bar->win; for (c = m->stack; c; c = c->snext) if (!c->isfloating && ISVISIBLE(c)) { XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc); @@ -1532,8 +2884,65 @@ restack(Monitor *m) } XSync(dpy, False); while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); + #if WARP_PATCH && FLEXTILE_DELUXE_LAYOUT || WARP_PATCH && MONOCLE_LAYOUT + #if FLEXTILE_DELUXE_LAYOUT + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + #endif // FLEXTILE_DELUXE_LAYOUT + if (m == selmon && (m->tagset[m->seltags] & m->sel->tags) && ( + #if MONOCLE_LAYOUT && FLEXTILE_DELUXE_LAYOUT + (m->lt[m->sellt]->arrange != &monocle + && !(m->ltaxis[MASTER] == MONOCLE && (abs(m->ltaxis[LAYOUT] == NO_SPLIT || !m->nmaster || n <= m->nmaster)))) + #elif MONOCLE_LAYOUT + m->lt[m->sellt]->arrange != &monocle + #else + !(m->ltaxis[MASTER] == MONOCLE && (abs(m->ltaxis[LAYOUT] == NO_SPLIT || !m->nmaster || n <= m->nmaster))) + #endif // FLEXTILE_DELUXE_LAYOUT + || m->sel->isfloating) + ) + warp(m->sel); + #endif // WARP_PATCH } +#if IPC_PATCH +void +run(void) +{ + int event_count = 0; + const int MAX_EVENTS = 10; + struct epoll_event events[MAX_EVENTS]; + + XSync(dpy, False); + + /* main event loop */ + while (running) { + event_count = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); + + for (int i = 0; i < event_count; i++) { + int event_fd = events[i].data.fd; + DEBUG("Got event from fd %d\n", event_fd); + + if (event_fd == dpy_fd) { + // -1 means EPOLLHUP + if (handlexevent(events + i) == -1) + return; + } else if (event_fd == ipc_get_sock_fd()) { + ipc_handle_socket_epoll_event(events + i); + } else if (ipc_is_client_registered(event_fd)) { + if (ipc_handle_client_epoll_event(events + i, mons, &lastselmon, selmon, + NUMTAGS, layouts, LENGTH(layouts)) < 0) { + fprintf(stderr, "Error handling IPC event on fd %d\n", event_fd); + } + } else { + fprintf(stderr, "Got event from unknown fd %d, ptr %p, u32 %d, u64 %lu", + event_fd, events[i].data.ptr, events[i].data.u32, + events[i].data.u64); + fprintf(stderr, " with events %d\n", events[i].events); + return; + } + } + } +} +#else void run(void) { @@ -1544,10 +2953,15 @@ run(void) if (handler[ev.type]) handler[ev.type](&ev); /* call handler */ } +#endif // IPC_PATCH void scan(void) { + #if SWALLOW_PATCH + scanner = 1; + char swin[256]; + #endif // SWALLOW_PATCH unsigned int i, num; Window d1, d2, *wins = NULL; XWindowAttributes wa; @@ -1557,8 +2971,17 @@ scan(void) if (!XGetWindowAttributes(dpy, wins[i], &wa) || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) continue; + #if BAR_ANYBAR_PATCH + if (wmclasscontains(wins[i], altbarclass, "")) + managealtbar(wins[i], &wa); + else + #endif // BAR_ANYBAR_PATCH if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) manage(wins[i], &wa); + #if SWALLOW_PATCH + else if (gettextprop(wins[i], netatom[NetClientList], swin, sizeof swin)) + manage(wins[i], &wa); + #endif // SWALLOW_PATCH } for (i = 0; i < num; i++) { /* now the transients */ if (!XGetWindowAttributes(dpy, wins[i], &wa)) @@ -1567,25 +2990,66 @@ scan(void) && (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)) manage(wins[i], &wa); } - if (wins) - XFree(wins); + XFree(wins); } + #if SWALLOW_PATCH + scanner = 0; + #endif // SWALLOW_PATCH } void sendmon(Client *c, Monitor *m) { + #if EXRESIZE_PATCH + Monitor *oldm = selmon; + #endif // EXRESIZE_PATCH if (c->mon == m) return; - unfocus(c, 1); + #if SENDMON_KEEPFOCUS_PATCH && !EXRESIZE_PATCH + int hadfocus = (c == selmon->sel); + #endif // SENDMON_KEEPFOCUS_PATCH + unfocus(c, 1, NULL); detach(c); detachstack(c); + #if SENDMON_KEEPFOCUS_PATCH && !EXRESIZE_PATCH + arrange(c->mon); + #endif // SENDMON_KEEPFOCUS_PATCH c->mon = m; + #if SCRATCHPADS_PATCH + if (!(c->tags & SPTAGMASK)) + #endif // SCRATCHPADS_PATCH + #if EMPTYVIEW_PATCH + c->tags = (m->tagset[m->seltags] ? m->tagset[m->seltags] : 1); + #else c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ + #endif // EMPTYVIEW_PATCH + #if ATTACHABOVE_PATCH || ATTACHASIDE_PATCH || ATTACHBELOW_PATCH || ATTACHBOTTOM_PATCH + attachx(c); + #else attach(c); + #endif attachstack(c); + #if EXRESIZE_PATCH + if (oldm != m) + arrange(oldm); + arrange(m); + focus(c); + restack(m); + #elif SENDMON_KEEPFOCUS_PATCH + arrange(m); + if (hadfocus) { + focus(c); + restack(m); + } else + focus(NULL); + #else focus(NULL); arrange(NULL); + #endif // EXRESIZE_PATCH / SENDMON_KEEPFOCUS_PATCH + #if SWITCHTAG_PATCH + if (c->switchtag) + c->switchtag = 0; + #endif // SWITCHTAG_PATCH } void @@ -1596,31 +3060,55 @@ setclientstate(Client *c, long state) XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, PropModeReplace, (unsigned char *)data, 2); } -void -setcurrentdesktop(void){ - long data[] = { 0 }; - XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); -} -void setdesktopnames(void){ - XTextProperty text; - Xutf8TextListToTextProperty(dpy, tags, TAGSLENGTH, XUTF8StringStyle, &text); - XSetTextProperty(dpy, root, &text, netatom[NetDesktopNames]); -} int +#if BAR_SYSTRAY_PATCH +sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) +#else sendevent(Client *c, Atom proto) +#endif // BAR_SYSTRAY_PATCH { int n; Atom *protocols; + #if BAR_SYSTRAY_PATCH + Atom mt; + #endif // BAR_SYSTRAY_PATCH int exists = 0; XEvent ev; + #if BAR_SYSTRAY_PATCH + if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { + mt = wmatom[WMProtocols]; + if (XGetWMProtocols(dpy, w, &protocols, &n)) { + while (!exists && n--) + exists = protocols[n] == proto; + XFree(protocols); + } + } else { + exists = True; + mt = proto; + } + #else if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { while (!exists && n--) exists = protocols[n] == proto; XFree(protocols); } + #endif // BAR_SYSTRAY_PATCH + if (exists) { + #if BAR_SYSTRAY_PATCH + ev.type = ClientMessage; + ev.xclient.window = w; + ev.xclient.message_type = mt; + ev.xclient.format = 32; + ev.xclient.data.l[0] = d0; + ev.xclient.data.l[1] = d1; + ev.xclient.data.l[2] = d2; + ev.xclient.data.l[3] = d3; + ev.xclient.data.l[4] = d4; + XSendEvent(dpy, w, False, mask, &ev); + #else ev.type = ClientMessage; ev.xclient.window = c->win; ev.xclient.message_type = wmatom[WMProtocols]; @@ -1628,16 +3116,11 @@ sendevent(Client *c, Atom proto) ev.xclient.data.l[0] = proto; ev.xclient.data.l[1] = CurrentTime; XSendEvent(dpy, c->win, False, NoEventMask, &ev); + #endif // BAR_SYSTRAY_PATCH } return exists; } -void -setnumdesktops(void){ - long data[] = { TAGSLENGTH }; - XChangeProperty(dpy, root, netatom[NetNumberOfDesktops], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); -} - void setfocus(Client *c) { @@ -1647,9 +3130,76 @@ setfocus(Client *c) XA_WINDOW, 32, PropModeReplace, (unsigned char *) &(c->win), 1); } + #if BAR_SYSTRAY_PATCH + sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); + #else sendevent(c, wmatom[WMTakeFocus]); + #endif // BAR_SYSTRAY_PATCH } +#if FAKEFULLSCREEN_CLIENT_PATCH && !FAKEFULLSCREEN_PATCH +void +setfullscreen(Client *c, int fullscreen) +{ + int savestate = 0, restorestate = 0; + + if ((c->fakefullscreen == 0 && fullscreen && !c->isfullscreen) // normal fullscreen + || (c->fakefullscreen == 2 && fullscreen)) // fake fullscreen --> actual fullscreen + savestate = 1; // go actual fullscreen + else if ((c->fakefullscreen == 0 && !fullscreen && c->isfullscreen) // normal fullscreen exit + || (c->fakefullscreen >= 2 && !fullscreen)) // fullscreen exit --> fake fullscreen + restorestate = 1; // go back into tiled + + /* If leaving fullscreen and the window was previously fake fullscreen (2), then restore + * that while staying in fullscreen. The exception to this is if we are in said state, but + * the client itself disables fullscreen (3) then we let the client go out of fullscreen + * while keeping fake fullscreen enabled (as otherwise there will be a mismatch between the + * client and the window manager's perception of the client's fullscreen state). */ + if (c->fakefullscreen == 2 && !fullscreen && c->isfullscreen) { + c->fakefullscreen = 1; + c->isfullscreen = 1; + fullscreen = 1; + } else if (c->fakefullscreen == 3) // client exiting actual fullscreen + c->fakefullscreen = 1; + + if (fullscreen != c->isfullscreen) { // only send property change if necessary + if (fullscreen) + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, + PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); + else + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, + PropModeReplace, (unsigned char*)0, 0); + } + + c->isfullscreen = fullscreen; + + /* Some clients, e.g. firefox, will send a client message informing the window manager + * that it is going into fullscreen after receiving the above signal. This has the side + * effect of this function (setfullscreen) sometimes being called twice when toggling + * fullscreen on and off via the window manager as opposed to the application itself. + * To protect against obscure issues where the client settings are stored or restored + * when they are not supposed to we add an additional bit-lock on the old state so that + * settings can only be stored and restored in that precise order. */ + if (savestate && !(c->oldstate & (1 << 1))) { + c->oldbw = c->bw; + c->oldstate = c->isfloating | (1 << 1); + 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 (restorestate && (c->oldstate & (1 << 1))) { + c->bw = c->oldbw; + c->isfloating = c->oldstate = c->oldstate & 1; + 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); + restack(c->mon); + } else + resizeclient(c, c->x, c->y, c->w, c->h); +} +#else void setfullscreen(Client *c, int fullscreen) { @@ -1657,34 +3207,80 @@ setfullscreen(Client *c, int fullscreen) XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); c->isfullscreen = 1; - c->oldstate = c->isfloating; + #if !FAKEFULLSCREEN_PATCH c->oldbw = c->bw; + c->oldstate = c->isfloating; c->bw = 0; c->isfloating = 1; resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); XRaiseWindow(dpy, c->win); + #endif // !FAKEFULLSCREEN_PATCH } 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; + #if !FAKEFULLSCREEN_PATCH c->bw = c->oldbw; + c->isfloating = c->oldstate; 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); + #endif // !FAKEFULLSCREEN_PATCH } } +#endif // FAKEFULLSCREEN_CLIENT_PATCH void setlayout(const Arg *arg) { - if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) - selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; + if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) { + #if PERTAG_PATCH + selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; + #else + selmon->sellt ^= 1; + #endif // PERTAG_PATCH + #if EXRESIZE_PATCH + 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); + } + } + } + #endif // EXRESIZE_PATCH + } if (arg && arg->v) - selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; + #if PERTAG_PATCH + selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + #else + selmon->lt[selmon->sellt] = (Layout *)arg->v; + #endif // PERTAG_PATCH + + #if FLEXTILE_DELUXE_LAYOUT + if (selmon->lt[selmon->sellt]->preset.nmaster && selmon->lt[selmon->sellt]->preset.nmaster != -1) + selmon->nmaster = selmon->lt[selmon->sellt]->preset.nmaster; + if (selmon->lt[selmon->sellt]->preset.nstack && selmon->lt[selmon->sellt]->preset.nstack != -1) + selmon->nstack = selmon->lt[selmon->sellt]->preset.nstack; + + selmon->ltaxis[LAYOUT] = selmon->lt[selmon->sellt]->preset.layout; + selmon->ltaxis[MASTER] = selmon->lt[selmon->sellt]->preset.masteraxis; + selmon->ltaxis[STACK] = selmon->lt[selmon->sellt]->preset.stack1axis; + selmon->ltaxis[STACK2] = selmon->lt[selmon->sellt]->preset.stack2axis; + + #if PERTAG_PATCH + selmon->pertag->ltaxis[selmon->pertag->curtag][LAYOUT] = selmon->ltaxis[LAYOUT]; + selmon->pertag->ltaxis[selmon->pertag->curtag][MASTER] = selmon->ltaxis[MASTER]; + selmon->pertag->ltaxis[selmon->pertag->curtag][STACK] = selmon->ltaxis[STACK]; + selmon->pertag->ltaxis[selmon->pertag->curtag][STACK2] = selmon->ltaxis[STACK2]; + #endif // PERTAG_PATCH + #endif // FLEXTILE_DELUXE_LAYOUT strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); if (selmon->sel) arrange(selmon); @@ -1692,23 +3288,6 @@ 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) @@ -1720,7 +3299,11 @@ 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; + #if PERTAG_PATCH selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; + #else + selmon->mfact = f; + #endif // PERTAG_PATCH arrange(selmon); } @@ -1734,54 +3317,137 @@ setup(void) /* clean up any zombies immediately */ sigchld(0); + #if RESTARTSIG_PATCH + signal(SIGHUP, sighup); + signal(SIGTERM, sigterm); + #endif // RESTARTSIG_PATCH + /* init screen */ screen = DefaultScreen(dpy); sw = DisplayWidth(dpy, screen); sh = DisplayHeight(dpy, screen); root = RootWindow(dpy, screen); + #if BAR_ALPHA_PATCH + xinitvisual(); + drw = drw_create(dpy, screen, root, sw, sh, visual, depth, cmap); + #else drw = drw_create(dpy, screen, root, sw, sh); + #endif // BAR_ALPHA_PATCH + #if BAR_PANGO_PATCH + if (!drw_font_create(drw, font)) + #else if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) + #endif // BAR_PANGO_PATCH die("no fonts could be loaded."); - lrpad = tag_padding ? tag_padding : drw->fonts->h; - bh = user_bh ? user_bh : drw->fonts->h + 2; + #if BAR_STATUSPADDING_PATCH + lrpad = drw->fonts->h + horizpadbar; + bh = drw->fonts->h + vertpadbar; + #else + lrpad = drw->fonts->h; + #if BAR_HEIGHT_PATCH + bh = bar_height ? bar_height : drw->fonts->h + 2; + #else + bh = drw->fonts->h + 2; + #endif // BAR_HEIGHT_PATCH + #endif // BAR_STATUSPADDING_PATCH updategeom(); - sp = sidepad; - vp = (topbar == 1) ? vertpad : - vertpad; - /* 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); + #if WINDOWROLERULE_PATCH + wmatom[WMWindowRole] = XInternAtom(dpy, "WM_WINDOW_ROLE", False); + #endif // WINDOWROLERULE_PATCH netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); + #if BAR_SYSTRAY_PATCH + netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False); + netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); + netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); + netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False); + netatom[NetSystemTrayVisual] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_VISUAL", False); + netatom[NetWMWindowTypeDock] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); + xatom[Manager] = XInternAtom(dpy, "MANAGER", False); + xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); + xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); + #endif // BAR_SYSTRAY_PATCH + #if BAR_EWMHTAGS_PATCH + netatom[NetDesktopViewport] = XInternAtom(dpy, "_NET_DESKTOP_VIEWPORT", False); + netatom[NetNumberOfDesktops] = XInternAtom(dpy, "_NET_NUMBER_OF_DESKTOPS", False); + netatom[NetCurrentDesktop] = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False); + netatom[NetDesktopNames] = XInternAtom(dpy, "_NET_DESKTOP_NAMES", False); + #endif // BAR_EWMHTAGS_PATCH 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); + #if NET_CLIENT_LIST_STACKING_PATCH netatom[NetClientListStacking] = XInternAtom(dpy, "_NET_CLIENT_LIST_STACKING", False); - - netatom[NetDesktopViewport] = XInternAtom(dpy, "_NET_DESKTOP_VIEWPORT", False); - netatom[NetNumberOfDesktops] = XInternAtom(dpy, "_NET_NUMBER_OF_DESKTOPS", False); - netatom[NetCurrentDesktop] = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False); - netatom[NetDesktopNames] = XInternAtom(dpy, "_NET_DESKTOP_NAMES", False); + #endif // NET_CLIENT_LIST_STACKING_PATCH + #if DECORATION_HINTS_PATCH + motifatom = XInternAtom(dpy, "_MOTIF_WM_HINTS", False); + #endif // DECORATION_HINTS_PATCH /* init cursors */ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); - cursor[CurHand] = drw_cur_create(drw, XC_hand2); cursor[CurResize] = drw_cur_create(drw, XC_sizing); + #if RESIZEPOINT_PATCH || RESIZECORNERS_PATCH + cursor[CurResizeBR] = drw_cur_create(drw, XC_bottom_right_corner); + cursor[CurResizeBL] = drw_cur_create(drw, XC_bottom_left_corner); + cursor[CurResizeTR] = drw_cur_create(drw, XC_top_right_corner); + cursor[CurResizeTL] = drw_cur_create(drw, XC_top_left_corner); + #endif // RESIZEPOINT_PATCH | RESIZECORNERS_PATCH + #if DRAGMFACT_PATCH + cursor[CurResizeHorzArrow] = drw_cur_create(drw, XC_sb_h_double_arrow); + cursor[CurResizeVertArrow] = drw_cur_create(drw, XC_sb_v_double_arrow); + #endif // DRAGMFACT_PATCH + #if DRAGCFACT_PATCH + cursor[CurIronCross] = drw_cur_create(drw, XC_iron_cross); + #endif // DRAGCFACT_PATCH cursor[CurMove] = drw_cur_create(drw, XC_fleur); /* init appearance */ + #if BAR_VTCOLORS_PATCH + get_vt_colors(); + if (get_luminance(colors[SchemeTagsNorm][ColBg]) > 50) { + strcpy(colors[SchemeTitleNorm][ColBg], title_bg_light); + strcpy(colors[SchemeTitleSel][ColBg], title_bg_light); + } else { + strcpy(colors[SchemeTitleNorm][ColBg], title_bg_dark); + strcpy(colors[SchemeTitleSel][ColBg], title_bg_dark); + } + #endif // BAR_VTCOLORS_PATCH + #if BAR_STATUS2D_PATCH && !BAR_STATUSCOLORS_PATCH + scheme = ecalloc(LENGTH(colors) + 1, sizeof(Clr *)); + #if BAR_ALPHA_PATCH + scheme[LENGTH(colors)] = drw_scm_create(drw, colors[0], alphas[0], ColCount); + #else + scheme[LENGTH(colors)] = drw_scm_create(drw, colors[0], ColCount); + #endif // BAR_ALPHA_PATCH + #else scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); + #endif // BAR_STATUS2D_PATCH for (i = 0; i < LENGTH(colors); i++) - scheme[i] = drw_scm_create(drw, colors[i], 3); - /* init bars */ + #if BAR_ALPHA_PATCH + scheme[i] = drw_scm_create(drw, colors[i], alphas[i], ColCount); + #else + scheme[i] = drw_scm_create(drw, colors[i], ColCount); + #endif // BAR_ALPHA_PATCH + #if BAR_POWERLINE_STATUS_PATCH + statusscheme = ecalloc(LENGTH(statuscolors), sizeof(Clr *)); + for (i = 0; i < LENGTH(statuscolors); i++) + #if BAR_ALPHA_PATCH + statusscheme[i] = drw_scm_create(drw, statuscolors[i], alphas[0], ColCount); + #else + statusscheme[i] = drw_scm_create(drw, statuscolors[i], ColCount); + #endif // BAR_ALPHA_PATCH + #endif // BAR_POWERLINE_STATUS_PATCH + updatebars(); updatestatus(); - updatebarpos(selmon); + /* supporting window for NetWMCheck */ wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0); XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32, @@ -1793,12 +3459,16 @@ setup(void) /* EWMH support per view */ XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, PropModeReplace, (unsigned char *) netatom, NetLast); + #if BAR_EWMHTAGS_PATCH setnumdesktops(); setcurrentdesktop(); setdesktopnames(); setviewport(); + #endif // BAR_EWMHTAGS_PATCH XDeleteProperty(dpy, root, netatom[NetClientList]); + #if NET_CLIENT_LIST_STACKING_PATCH XDeleteProperty(dpy, root, netatom[NetClientListStacking]); + #endif // NET_CLIENT_LIST_STACKING_PATCH /* select events */ wa.cursor = cursor[CurNormal]->cursor; wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask @@ -1808,11 +3478,13 @@ setup(void) XSelectInput(dpy, root, wa.event_mask); grabkeys(); focus(NULL); -} -void -setviewport(void){ - long data[] = { 0, 0 }; - XChangeProperty(dpy, root, netatom[NetDesktopViewport], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 2); + #if IPC_PATCH + setupepoll(); + #endif // IPC_PATCH + #if BAR_ANYBAR_PATCH + if (usealtbar) + spawnbar(); + #endif // BAR_ANYBAR_PATCH } @@ -1835,9 +3507,50 @@ showhide(Client *c) if (!c) return; if (ISVISIBLE(c)) { + #if SCRATCHPADS_PATCH && SCRATCHPADS_KEEP_POSITION_AND_SIZE_PATCH + if ( + (c->tags & SPTAGMASK) && + c->isfloating && + ( + c->x < c->mon->mx || + c->x > c->mon->mx + c->mon->mw || + c->y < c->mon->my || + c->y > c->mon->my + c->mon->mh + ) + ) { + c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2); + c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2); + } + #elif SCRATCHPADS_PATCH + 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); + } + #endif // SCRATCHPADS_KEEP_POSITION_AND_SIZE_PATCH | SCRATCHPADS_PATCH /* show clients top down */ + #if SAVEFLOATS_PATCH || EXRESIZE_PATCH + if (!c->mon->lt[c->mon->sellt]->arrange && c->sfx != -9999 && !c->isfullscreen) { + XMoveWindow(dpy, c->win, c->sfx, c->sfy); + resize(c, c->sfx, c->sfy, c->sfw, c->sfh, 0); + showhide(c->snext); + return; + } + #endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH + #if AUTORESIZE_PATCH + if (c->needresize) { + c->needresize = 0; + XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); + } else { + XMoveWindow(dpy, c->win, c->x, c->y); + } + #else XMoveWindow(dpy, c->win, c->x, c->y); - if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen) + #endif // AUTORESIZE_PATCH + if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) + #if !FAKEFULLSCREEN_PATCH + && !c->isfullscreen + #endif // !FAKEFULLSCREEN_PATCH + ) resize(c, c->x, c->y, c->w, c->h, 0); showhide(c->snext); } else { @@ -1850,179 +3563,259 @@ showhide(Client *c) void sigchld(int unused) { + #if COOL_AUTOSTART_PATCH + pid_t pid; + #endif // COOL_AUTOSTART_PATCH if (signal(SIGCHLD, sigchld) == SIG_ERR) die("can't install SIGCHLD handler:"); + #if COOL_AUTOSTART_PATCH + while (0 < (pid = waitpid(-1, NULL, WNOHANG))) { + pid_t *p, *lim; + + if (!(p = autostart_pids)) + continue; + lim = &p[autostart_len]; + + for (; p < lim; p++) { + if (*p == pid) { + *p = -1; + break; + } + } + } + #else while (0 < waitpid(-1, NULL, WNOHANG)); + #endif // COOL_AUTOSTART_PATCH } +#if RIODRAW_PATCH void -sigdwmblocks(const Arg *arg) +spawn(const Arg *arg) { - int fd; - struct flock fl; - union sigval sv; - - if (dwmblockssig <= 0 || dwmblockssig >= 10) - return; - sv.sival_int = (dwmblockssig << 8) | arg->i; - fd = open(DWMBLOCKSLOCKFILE, O_RDONLY); - if (fd == -1) - return; - fl.l_type = F_WRLCK; - fl.l_start = 0; - fl.l_whence = SEEK_SET; - fl.l_len = 0; - if (fcntl(fd, F_GETLK, &fl) == -1 || fl.l_type == F_UNLCK) - return; - sigqueue(fl.l_pid, SIGRTMIN, sv); + spawncmd(arg); } +pid_t +spawncmd(const Arg *arg) +#else void spawn(const Arg *arg) +#endif // RIODRAW_PATCH { - if (fork() == 0) { + #if RIODRAW_PATCH + pid_t pid; + #endif // RIODRAW_PATCH + #if BAR_STATUSCMD_PATCH && !BAR_DWMBLOCKS_PATCH + char *cmd = NULL; + #endif // BAR_STATUSCMD_PATCH | BAR_DWMBLOCKS_PATCH + #if !NODMENU_PATCH + if (arg->v == dmenucmd) + dmenumon[0] = '0' + selmon->num; + #endif // NODMENU_PATCH + #if BAR_STATUSCMD_PATCH && !BAR_DWMBLOCKS_PATCH + #if !NODMENU_PATCH + else if (arg->v == statuscmd) + #else + if (arg->v == statuscmd) + #endif // NODMENU_PATCH + { + int len = strlen(statuscmds[statuscmdn]) + 1; + if (!(cmd = malloc(sizeof(char)*len + sizeof(statusexport)))) + die("malloc:"); + strcpy(cmd, statusexport); + strcat(cmd, statuscmds[statuscmdn]); + cmd[LENGTH(statusexport)-3] = '0' + lastbutton; + statuscmd[2] = cmd; + } + #endif // BAR_STATUSCMD_PATCH | BAR_DWMBLOCKS_PATCH + + #if RIODRAW_PATCH + if ((pid = fork()) == 0) + #else + if (fork() == 0) + #endif // RIODRAW_PATCH + { if (dpy) close(ConnectionNumber(dpy)); + #if SPAWNCMD_PATCH + if (selmon->sel) { + const char* const home = getenv("HOME"); + assert(home && strchr(home, '/')); + const size_t homelen = strlen(home); + char *cwd, *pathbuf = NULL; + struct stat statbuf; + + cwd = strtok(selmon->sel->name, SPAWN_CWD_DELIM); + /* NOTE: strtok() alters selmon->sel->name in-place, + * but that does not matter because we are going to + * exec() below anyway; nothing else will use it */ + while (cwd) { + if (*cwd == '~') { /* replace ~ with $HOME */ + if (!(pathbuf = malloc(homelen + strlen(cwd)))) /* ~ counts for NULL term */ + die("fatal: could not malloc() %u bytes\n", homelen + strlen(cwd)); + strcpy(strcpy(pathbuf, home) + homelen, cwd + 1); + cwd = pathbuf; + } + + if (strchr(cwd, '/') && !stat(cwd, &statbuf)) { + if (!S_ISDIR(statbuf.st_mode)) + cwd = dirname(cwd); + + if (!chdir(cwd)) + break; + } + + cwd = strtok(NULL, SPAWN_CWD_DELIM); + } + + free(pathbuf); + } + #endif // SPAWNCMD_PATCH setsid(); execvp(((char **)arg->v)[0], (char **)arg->v); fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]); perror(" failed"); exit(EXIT_SUCCESS); } -} - -void -switchcol(const Arg *arg) -{ - Client *c, *t; - int col = 0; - int i; - - if (!selmon->sel) - return; - for (i = 0, c = nexttiled(selmon->clients); c ; - c = nexttiled(c->next), i++) { - if (c == selmon->sel) - col = (i + 1) > selmon->nmaster; - } - if (i <= selmon->nmaster) - return; - for (c = selmon->stack; c; c = c->snext) { - if (!ISVISIBLE(c)) - continue; - for (i = 0, t = nexttiled(selmon->clients); t && t != c; - t = nexttiled(t->next), i++); - if (t && (i + 1 > selmon->nmaster) != col) { - focus(c); - restack(selmon); - break; - } - } + #if BAR_STATUSCMD_PATCH && !BAR_DWMBLOCKS_PATCH + free(cmd); + #endif // BAR_STATUSCMD_PATCH | BAR_DWMBLOCKS_PATCH + #if RIODRAW_PATCH + return pid; + #endif // RIODRAW_PATCH } void tag(const Arg *arg) { + #if SWAPFOCUS_PATCH && PERTAG_PATCH + unsigned int tagmask, tagindex; + #endif // SWAPFOCUS_PATCH + if (selmon->sel && arg->ui & TAGMASK) { selmon->sel->tags = arg->ui & TAGMASK; + #if SWITCHTAG_PATCH + if (selmon->sel->switchtag) + selmon->sel->switchtag = 0; + #endif // SWITCHTAG_PATCH focus(NULL); + #if SWAPFOCUS_PATCH && PERTAG_PATCH + selmon->pertag->prevclient[selmon->pertag->curtag] = NULL; + for (tagmask = arg->ui & TAGMASK, tagindex = 1; tagmask!=0; tagmask >>= 1, tagindex++) + if (tagmask & 1) + selmon->pertag->prevclient[tagindex] = NULL; + #endif // SWAPFOCUS_PATCH arrange(selmon); + #if VIEWONTAG_PATCH + if ((arg->ui & TAGMASK) != selmon->tagset[selmon->seltags]) + view(arg); + #endif // VIEWONTAG_PATCH } - updatecurrentdesktop(); } void tagmon(const Arg *arg) { + #if TAGMONFIXFS_PATCH + Client *c = selmon->sel; + if (!c || !mons->next) + return; + if (c->isfullscreen) { + c->isfullscreen = 0; + sendmon(c, dirtomon(arg->i)); + c->isfullscreen = 1; + #if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH + if (c->fakefullscreen != 1) { + resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); + XRaiseWindow(dpy, c->win); + } + #elif !FAKEFULLSCREEN_PATCH + resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); + XRaiseWindow(dpy, c->win); + #endif // FAKEFULLSCREEN_CLIENT_PATCH + } else + sendmon(c, dirtomon(arg->i)); + #else if (!selmon->sel || !mons->next) return; sendmon(selmon->sel, dirtomon(arg->i)); -} - -void -tile(Monitor *m) -{ - unsigned int i, n, h, mw, my, ty; - float mfacts = 0, sfacts = 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; - } - if (n == 0) - return; - - if (n > m->nmaster) - mw = m->nmaster - ? m->ww * (m->rmaster ? 1.0 - m->mfact : 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) * (c->cfact / mfacts); - resize(c, m->rmaster ? m->wx + m->ww - mw : m->wx, - m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); - if (my + HEIGHT(c) < m->wh) - my += HEIGHT(c); - mfacts -= c->cfact; - } else { - h = (m->wh - ty) * (c->cfact / sfacts); - resize(c, m->rmaster ? m->wx : 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); - sfacts -= c->cfact; - } + #endif // TAGMONFIXFS_PATCH } void togglebar(const Arg *arg) { + Bar *bar; + #if BAR_HOLDBAR_PATCH && PERTAG_PATCH && PERTAGBAR_PATCH + selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = (selmon->showbar == 2 ? 1 : !selmon->showbar); + #elif BAR_HOLDBAR_PATCH + selmon->showbar = (selmon->showbar == 2 ? 1 : !selmon->showbar); + #elif PERTAG_PATCH && PERTAGBAR_PATCH selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; + #else + selmon->showbar = !selmon->showbar; + #endif // BAR_HOLDBAR_PATCH | PERTAG_PATCH updatebarpos(selmon); - XMoveResizeWindow(dpy, selmon->barwin, selmon->wx + sp, selmon->by + vp, selmon->ww - 2 * sp, bh); + for (bar = selmon->bar; bar; bar = bar->next) + XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh); arrange(selmon); } void togglefloating(const Arg *arg) { - if (!selmon->sel) + Client *c = selmon->sel; + if (arg && arg->v) + c = (Client*)arg->v; + if (!c) return; - if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ + #if !FAKEFULLSCREEN_PATCH + #if FAKEFULLSCREEN_CLIENT_PATCH + if (c->isfullscreen && c->fakefullscreen != 1) /* 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, 0); - arrange(selmon); -} - -void -togglefullscr(const Arg *arg) -{ - if(selmon->sel) - setfullscreen(selmon->sel, !selmon->sel->isfullscreen); -} + #else + if (c->isfullscreen) /* no support for fullscreen windows */ + return; + #endif // FAKEFULLSCREEN_CLIENT_PATCH + #endif // !FAKEFULLSCREEN_PATCH + c->isfloating = !c->isfloating || c->isfixed; + #if !BAR_FLEXWINTITLE_PATCH + if (c->isfloating) + XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColFloat].pixel); + else + XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); + #endif // BAR_FLEXWINTITLE_PATCH + if (c->isfloating) { + #if SAVEFLOATS_PATCH || EXRESIZE_PATCH + if (c->sfx != -9999) { + /* restore last known float dimensions */ + resize(c, c->sfx, c->sfy, c->sfw, c->sfh, 0); + } else + #endif // SAVEFLOATS_PATCH // EXRESIZE_PATCH + resize(c, c->x, c->y, c->w, c->h, 0); + #if SAVEFLOATS_PATCH || EXRESIZE_PATCH + } else { + /* save last known float dimensions */ + c->sfx = c->x; + c->sfy = c->y; + c->sfw = c->w; + c->sfh = c->h; + #endif // SAVEFLOATS_PATCH / EXRESIZE_PATCH + } + arrange(c->mon); -void -togglermaster(const Arg *arg) -{ - selmon->rmaster = !selmon->rmaster; - /* now mfact represents the left factor */ - selmon->mfact = 1.0 - selmon->mfact; - if (selmon->lt[selmon->sellt]->arrange) - arrange(selmon); + #if BAR_EWMHTAGS_PATCH + setfloatinghint(c); + #endif // BAR_EWMHTAGS_PATCH } void toggletag(const Arg *arg) { unsigned int newtags; + #if SWAPFOCUS_PATCH && PERTAG_PATCH + unsigned int tagmask, tagindex; + #endif // SWAPFOCUS_PATCH if (!selmon->sel) return; @@ -2030,25 +3823,74 @@ toggletag(const Arg *arg) if (newtags) { selmon->sel->tags = newtags; focus(NULL); + #if SWAPFOCUS_PATCH && PERTAG_PATCH + for (tagmask = arg->ui & TAGMASK, tagindex = 1; tagmask!=0; tagmask >>= 1, tagindex++) + if (tagmask & 1) + selmon->pertag->prevclient[tagindex] = NULL; + #endif // SWAPFOCUS_PATCH arrange(selmon); } + #if BAR_EWMHTAGS_PATCH updatecurrentdesktop(); + #endif // BAR_EWMHTAGS_PATCH } void toggleview(const Arg *arg) { unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + #if PERTAG_PATCH int i; + #endif // PERTAG_PATCH + + #if TAGINTOSTACK_ALLMASTER_PATCH + Client *const selected = selmon->sel; + // clients in the master area should be the same after we add a new tag + Client **const masters = calloc(selmon->nmaster, sizeof(Client *)); + if (!masters) { + die("fatal: could not calloc() %u bytes \n", selmon->nmaster * sizeof(Client *)); + } + // collect (from last to first) references to all clients in the master area + Client *c; + size_t j; + for (c = nexttiled(selmon->clients), j = 0; c && j < selmon->nmaster; c = nexttiled(c->next), ++j) + masters[selmon->nmaster - (j + 1)] = c; + // put the master clients at the front of the list + // > go from the 'last' master to the 'first' + for (j = 0; j < selmon->nmaster; ++j) + if (masters[j]) + pop(masters[j]); + free(masters); + + // we also want to be sure not to mutate the focus + focus(selected); + #elif TAGINTOSTACK_ONEMASTER_PATCH + // the first visible client should be the same after we add a new tag + // we also want to be sure not to mutate the focus + Client *const c = nexttiled(selmon->clients); + if (c) { + Client * const selected = selmon->sel; + pop(c); + focus(selected); + } + #endif // TAGINTOSTACK_ALLMASTER_PATCH / TAGINTOSTACK_ONEMASTER_PATCH + + #if !EMPTYVIEW_PATCH if (newtagset) { + #endif // EMPTYVIEW_PATCH selmon->tagset[selmon->seltags] = newtagset; - if (newtagset == ~0) { + #if PERTAG_PATCH + #if SCRATCHPADS_PATCH + if (newtagset == ~SPTAGMASK) + #else + if (newtagset == ~0) + #endif // SCRATCHPADS_PATCH + { 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; @@ -2062,22 +3904,45 @@ toggleview(const Arg *arg) 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 PERTAGBAR_PATCH if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) togglebar(NULL); - + #endif // PERTAGBAR_PATCH + #endif // PERTAG_PATCH focus(NULL); arrange(selmon); + #if !EMPTYVIEW_PATCH } + #endif // EMPTYVIEW_PATCH + #if BAR_EWMHTAGS_PATCH + updatecurrentdesktop(); + #endif // BAR_EWMHTAGS_PATCH } void -unfocus(Client *c, int setfocus) +unfocus(Client *c, int setfocus, Client *nextfocus) { if (!c) return; + #if SWAPFOCUS_PATCH && PERTAG_PATCH + selmon->pertag->prevclient[selmon->pertag->curtag] = c; + #endif // SWAPFOCUS_PATCH + #if LOSEFULLSCREEN_PATCH + if (c->isfullscreen && ISVISIBLE(c) && c->mon == selmon && nextfocus && !nextfocus->isfloating) + #if FAKEFULLSCREEN_CLIENT_PATCH + if (c->fakefullscreen != 1) + setfullscreen(c, 0); + #else + setfullscreen(c, 0); + #endif // #if FAKEFULLSCREEN_CLIENT_PATCH + #endif // LOSEFULLSCREEN_PATCH grabbuttons(c, 0); - XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); + #if !BAR_FLEXWINTITLE_PATCH + if (c->isfloating) + XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColFloat].pixel); + else + XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); + #endif // BAR_FLEXWINTITLE_PATCH if (setfocus) { XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); XDeleteProperty(dpy, root, netatom[NetActiveWindow]); @@ -2088,8 +3953,27 @@ void unmanage(Client *c, int destroyed) { Monitor *m = c->mon; + #if SWITCHTAG_PATCH + unsigned int switchtag = c->switchtag; + #endif // SWITCHTAG_PATCH XWindowChanges wc; + #if SWALLOW_PATCH + if (c->swallowing) { + unswallow(c); + return; + } + + Client *s = swallowingclient(c->win); + if (s) { + free(s->swallowing); + s->swallowing = NULL; + arrange(m); + focus(NULL); + return; + } + #endif // SWALLOW_PATCH + detach(c); detachstack(c); if (!destroyed) { @@ -2104,15 +3988,27 @@ unmanage(Client *c, int destroyed) XUngrabServer(dpy); } free(c); + #if SWALLOW_PATCH + if (s) + return; + #endif // SWALLOW_PATCH focus(NULL); updateclientlist(); arrange(m); + #if SWITCHTAG_PATCH + if (switchtag && ((switchtag & TAGMASK) != selmon->tagset[selmon->seltags])) + view(&((Arg) { .ui = switchtag })); + #endif // SWITCHTAG_PATCH } void unmapnotify(XEvent *e) { Client *c; + #if BAR_ANYBAR_PATCH + Monitor *m; + Bar *bar; + #endif // BAR_ANYBAR_PATCH XUnmapEvent *ev = &e->xunmap; if ((c = wintoclient(ev->window))) { @@ -2120,78 +4016,111 @@ unmapnotify(XEvent *e) setclientstate(c, WithdrawnState); else unmanage(c, 0); + #if BAR_SYSTRAY_PATCH + } else if (showsystray && (c = wintosystrayicon(ev->window))) { + /* KLUDGE! sometimes icons occasionally unmap their windows, but do + * _not_ destroy them. We map those windows back */ + XMapRaised(dpy, c->win); + removesystrayicon(c); + drawbarwin(systray->bar); + #endif // BAR_SYSTRAY_PATCH } + #if BAR_ANYBAR_PATCH + else { + m = wintomon(ev->window); + for (bar = m->bar; bar; bar = bar->next) { + if (bar->win == ev->window) { + unmanagealtbar(ev->window); + break; + } + } + } + #endif // BAR_ANYBAR_PATCH } void updatebars(void) { + Bar *bar; Monitor *m; XSetWindowAttributes wa = { .override_redirect = True, + #if BAR_ALPHA_PATCH + .background_pixel = 0, + .border_pixel = 0, + .colormap = cmap, + #else .background_pixmap = ParentRelative, - .event_mask = ButtonPressMask|ExposureMask|PointerMotionMask + #endif // BAR_ALPHA_PATCH + .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, DefaultDepth(dpy, screen), - CopyFromParent, DefaultVisual(dpy, screen), - CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); - XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); - XMapRaised(dpy, m->barwin); - XSetClassHint(dpy, m->barwin, &ch); - } -} -void updatecurrentdesktop(void){ - long rawdata[] = { selmon->tagset[selmon->seltags] }; - int i=0; - while(*rawdata >> i+1){ - i++; + for (bar = m->bar; bar; bar = bar->next) { + if (bar->external) + continue; + if (!bar->win) { + #if BAR_ALPHA_PATCH + bar->win = XCreateWindow(dpy, root, bar->bx, bar->by, bar->bw, bar->bh, 0, depth, + InputOutput, visual, + CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa); + #else + bar->win = XCreateWindow(dpy, root, bar->bx, bar->by, bar->bw, bar->bh, 0, DefaultDepth(dpy, screen), + CopyFromParent, DefaultVisual(dpy, screen), + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + #endif // BAR_ALPHA_PATCH + XDefineCursor(dpy, bar->win, cursor[CurNormal]->cursor); + XMapRaised(dpy, bar->win); + XSetClassHint(dpy, bar->win, &ch); + } + } } - long data[] = { i }; - XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); -} - -void -updatebarcursor(int cursorpos) -{ - static int currentcursor = 0; - int x; - - if (BETWEEN(cursorpos, (x = selmon->ww - wstext + lrpad / 2), x + wstext - lrpad)) { - updatedwmblockssig(x, cursorpos); - if (currentcursor) { - if (dwmblockssig <= 0 || dwmblockssig >= 10) { - currentcursor = 0; - XDefineCursor(dpy, selmon->barwin, cursor[CurNormal]->cursor); - } - } else { - if (dwmblockssig > 0 && dwmblockssig < 10) { - currentcursor = 1; - XDefineCursor(dpy, selmon->barwin, cursor[CurHand]->cursor); - } - } - } else { - if (currentcursor) { - currentcursor = 0; - XDefineCursor(dpy, selmon->barwin, cursor[CurNormal]->cursor); - } - } } void updatebarpos(Monitor *m) { + m->wx = m->mx; m->wy = m->my; + m->ww = m->mw; 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; + Bar *bar; + #if BAR_PADDING_PATCH + int y_pad = vertpad; + int x_pad = sidepad; + #else + int y_pad = 0; + int x_pad = 0; + #endif // BAR_PADDING_PATCH + + #if INSETS_PATCH + // Custom insets + Inset inset = m->inset; + m->wx += inset.x; + m->wy += inset.y; + m->ww -= inset.w + inset.x; + m->wh -= inset.h + inset.y; + #endif // INSETS_PATCH + + for (bar = m->bar; bar; bar = bar->next) { + bar->bx = m->wx + x_pad; + bar->bw = m->ww - 2 * x_pad; + } + + for (bar = m->bar; bar; bar = bar->next) + if (!m->showbar || !bar->showbar) + bar->by = -bar->bh - y_pad; + if (!m->showbar) + return; + for (bar = m->bar; bar; bar = bar->next) { + if (!bar->showbar) + continue; + if (bar->topbar) + m->wy = m->wy + bar->bh + y_pad; + m->wh -= y_pad + bar->bh; + } + for (bar = m->bar; bar; bar = bar->next) + bar->by = (bar->topbar ? m->wy - bar->bh : m->wy + m->wh); } void @@ -2207,37 +4136,14 @@ updateclientlist() XA_WINDOW, 32, PropModeAppend, (unsigned char *) &(c->win), 1); + #if NET_CLIENT_LIST_STACKING_PATCH XDeleteProperty(dpy, root, netatom[NetClientListStacking]); for (m = mons; m; m = m->next) for (c = m->stack; c; c = c->snext) XChangeProperty(dpy, root, netatom[NetClientListStacking], XA_WINDOW, 32, PropModeAppend, (unsigned char *) &(c->win), 1); -} - -void -updatedwmblockssig(int x, int e) -{ - char *ts = stexts; - char *tp = stexts; - char ctmp; - - while (*ts != '\0') { - if ((unsigned char)*ts > 10) { - ts++; - continue; - } - ctmp = *ts; - *ts = '\0'; - x += TTEXTW(tp); - *ts = ctmp; - if (x >= e) { - dwmblockssig = (unsigned char)ctmp; - return; - } - tp = ++ts; - } - dwmblockssig = 0; + #endif // NET_CLIENT_LIST_STACKING_PATCH } int @@ -2261,6 +4167,9 @@ updategeom(void) memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo)); XFree(info); nn = j; + #if SORTSCREENS_PATCH + sortscreens(unique, nn); + #endif // SORTSCREENS_PATCH if (n <= nn) { /* new monitors available */ for (i = 0; i < (nn - n); i++) { for (m = mons; m && m->next; m = m->next); @@ -2269,7 +4178,7 @@ updategeom(void) else mons = createmon(); } - for (i = 0, m = mons; i < nn && m; m = m->next, i++) + 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) @@ -2282,6 +4191,7 @@ updategeom(void) m->mh = m->wh = unique[i].height; updatebarpos(m); } + } } else { /* less monitors available nn < n */ for (i = nn; i < n; i++) { for (m = mons; m && m->next; m = m->next); @@ -2298,6 +4208,8 @@ updategeom(void) cleanupmon(m); } } + for (i = 0, m = mons; m; m = m->next, i++) + m->index = i; free(unique); } else #endif /* XINERAMA */ @@ -2342,7 +4254,11 @@ updatesizehints(Client *c) if (!XGetWMNormalHints(dpy, c->win, &size, &msize)) /* size is uninitialized, ensure that size.flags aren't used */ + #if SIZEHINTS_PATCH || SIZEHINTS_RULED_PATCH + size.flags = 0; + #else size.flags = PSize; + #endif // SIZEHINTS_PATCH | SIZEHINTS_RULED_PATCH if (size.flags & PBaseSize) { c->basew = size.base_width; c->baseh = size.base_height; @@ -2374,54 +4290,78 @@ updatesizehints(Client *c) c->maxa = (float)size.max_aspect.x / size.max_aspect.y; } else c->maxa = c->mina = 0.0; + #if SIZEHINTS_PATCH || SIZEHINTS_RULED_PATCH + if (size.flags & PSize) { + c->basew = size.base_width; + c->baseh = size.base_height; + c->isfloating = 1; + } + #if SIZEHINTS_RULED_PATCH + checkfloatingrules(c); + #endif // SIZEHINTS_RULED_PATCH + #endif // SIZEHINTS_PATCH c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh); } void updatestatus(void) { - char rawstext[256]; - - if (gettextprop(root, XA_WM_NAME, rawstext, sizeof rawstext)) { - char stextt[256]; - char *stc = stextc, *sts = stexts, *stt = stextt; - - for (char *rt = rawstext; *rt != '\0'; rt++) - if ((unsigned char)*rt >= ' ') - *(stc++) = *(sts++) = *(stt++) = *rt; - else if ((unsigned char)*rt > 10) - *(stc++) = *rt; - else - *(sts++) = *rt; - *stc = *sts = *stt = '\0'; - wstext = TEXTW(stextt); - } else { - strcpy(stextc, "dwm-"VERSION); - strcpy(stexts, stextc); - wstext = TEXTW(stextc); - } - drawbar(selmon); + Monitor *m; + #if BAR_EXTRASTATUS_PATCH + if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) { + strcpy(stext, "dwm-"VERSION); + estext[0] = '\0'; + } else { + char *e = strchr(rawstext, statussep); + if (e) { + *e = '\0'; e++; + #if BAR_STATUSCMD_PATCH + strncpy(rawestext, e, sizeof(estext) - 1); + copyvalidchars(estext, rawestext); + #else + strncpy(estext, e, sizeof(estext) - 1); + #endif // BAR_STATUSCMD_PATCH + } else { + estext[0] = '\0'; + } + #if BAR_STATUSCMD_PATCH + copyvalidchars(stext, rawstext); + #else + strncpy(stext, rawstext, sizeof(stext) - 1); + #endif // BAR_STATUSCMD_PATCH + } + #elif BAR_STATUSCMD_PATCH + if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) + strcpy(stext, "dwm-"VERSION); + else + copyvalidchars(stext, rawstext); + #else + if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) + strcpy(stext, "dwm-"VERSION); + #endif // BAR_EXTRASTATUS_PATCH | BAR_STATUSCMD_PATCH + for (m = mons; m; m = m->next) + drawbar(m); } void updatetitle(Client *c) { + #if IPC_PATCH + char oldname[sizeof(c->name)]; + strcpy(oldname, c->name); + #endif // IPC_PATCH + 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]); - if (state == netatom[NetWMFullscreen]) - setfullscreen(c, 1); - if (wtype == netatom[NetWMWindowTypeDialog]) - c->isfloating = 1; + #if IPC_PATCH + for (Monitor *m = mons; m; m = m->next) { + if (m->sel == c && strcmp(oldname, c->name) != 0) + ipc_focused_title_change_event(m->num, c->win, oldname, c->name); + } + #endif // IPC_PATCH } void @@ -2435,6 +4375,12 @@ updatewmhints(Client *c) XSetWMHints(dpy, c->win, wmh); } else c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0; + if (c->isurgent) { + if (c->isfloating) + XSetWindowBorder(dpy, c->win, scheme[SchemeUrg][ColFloat].pixel); + else + XSetWindowBorder(dpy, c->win, scheme[SchemeUrg][ColBorder].pixel); + } if (wmh->flags & InputHint) c->neverfocus = !wmh->input; else @@ -2446,40 +4392,35 @@ updatewmhints(Client *c) void view(const Arg *arg) { - int i; - unsigned int tmptag; - + #if EMPTYVIEW_PATCH + if (arg->ui && (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + #else if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + #endif // EMPTYVIEW_PATCH + { + #if VIEW_SAME_TAG_GIVES_PREVIOUS_TAG_PATCH + view(&((Arg) { .ui = 0 })); + #endif // VIEW_SAME_TAG_GIVES_PREVIOUS_TAG_PATCH return; + } selmon->seltags ^= 1; /* toggle sel tagset */ - if (arg->ui & TAGMASK) { + #if PERTAG_PATCH + pertagview(arg); + #if SWAPFOCUS_PATCH + Client *unmodified = selmon->pertag->prevclient[selmon->pertag->curtag]; + #endif // SWAPFOCUS_PATCH + #else + 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); - + #endif // PERTAG_PATCH focus(NULL); + #if SWAPFOCUS_PATCH && PERTAG_PATCH + selmon->pertag->prevclient[selmon->pertag->curtag] = unmodified; + #endif // SWAPFOCUS_PATCH arrange(selmon); + #if BAR_EWMHTAGS_PATCH updatecurrentdesktop(); + #endif // BAR_EWMHTAGS_PATCH } Client * @@ -2501,37 +4442,19 @@ wintomon(Window w) int x, y; Client *c; Monitor *m; + Bar *bar; 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; + for (bar = m->bar; bar; bar = bar->next) + if (w == bar->win) + 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 (!(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. */ @@ -2572,197 +4495,183 @@ void zoom(const Arg *arg) { Client *c = selmon->sel; - - if (!selmon->lt[selmon->sellt]->arrange - || (selmon->sel && selmon->sel->isfloating)) + if (arg && arg->v) + c = (Client*)arg->v; + if (!c) + return; + #if ZOOMSWAP_PATCH + Client *at = NULL, *cold, *cprevious = NULL, *p; + #endif // ZOOMSWAP_PATCH + + #if ZOOMFLOATING_PATCH + if (c && c->isfloating) + togglefloating(&((Arg) { .v = c })); + #endif // ZOOMFLOATING_PATCH + + #if SWAPFOCUS_PATCH && PERTAG_PATCH + c->mon->pertag->prevclient[c->mon->pertag->curtag] = nexttiled(c->mon->clients); + #endif // SWAPFOCUS_PATCH + + if (!c->mon->lt[c->mon->sellt]->arrange + || (c && c->isfloating) + #if ZOOMSWAP_PATCH + || !c + #endif // ZOOMSWAP_PATCH + ) return; - if (c == nexttiled(selmon->clients)) + + #if ZOOMSWAP_PATCH + if (c == nexttiled(c->mon->clients)) { + #if PERTAG_PATCH + p = c->mon->pertag->prevzooms[c->mon->pertag->curtag]; + #else + p = prevzoom; + #endif // PERTAG_PATCH + at = findbefore(p); + if (at) + cprevious = nexttiled(at->next); + if (!cprevious || cprevious != p) { + #if PERTAG_PATCH + c->mon->pertag->prevzooms[c->mon->pertag->curtag] = NULL; + #else + prevzoom = NULL; + #endif // PERTAG_PATCH + #if SWAPFOCUS_PATCH && PERTAG_PATCH + if (!c || !(c = c->mon->pertag->prevclient[c->mon->pertag->curtag] = nexttiled(c->next))) + #else + if (!c || !(c = nexttiled(c->next))) + #endif // SWAPFOCUS_PATCH + return; + } else + #if SWAPFOCUS_PATCH && PERTAG_PATCH + c = c->mon->pertag->prevclient[c->mon->pertag->curtag] = cprevious; + #else + c = cprevious; + #endif // SWAPFOCUS_PATCH + } + + cold = nexttiled(c->mon->clients); + if (c != cold && !at) + at = findbefore(c); + detach(c); + attach(c); + /* swap windows instead of pushing the previous one down */ + if (c != cold && at) { + #if PERTAG_PATCH + c->mon->pertag->prevzooms[c->mon->pertag->curtag] = cold; + #else + prevzoom = cold; + #endif // PERTAG_PATCH + if (cold && at != cold) { + detach(cold); + cold->next = at->next; + at->next = cold; + } + } + focus(c); + arrange(c->mon); + #else + if (c == nexttiled(c->mon->clients)) + #if SWAPFOCUS_PATCH && PERTAG_PATCH + if (!c || !(c = c->mon->pertag->prevclient[c->mon->pertag->curtag] = nexttiled(c->next))) + #else if (!c || !(c = nexttiled(c->next))) + #endif // SWAPFOCUS_PATCH return; pop(c); + #endif // ZOOMSWAP_PATCH } int main(int argc, char *argv[]) { + #if CMDCUSTOMIZE_PATCH + for (int i=1;iclients); c; c = nexttiled(c->next), n++); - if (n == 0) - return; - - /* initialize areas */ - mw = m->ww; - mx = 0; - my = 0; - tw = mw; - - if (n > m->nmaster) { - /* go mfact box in the center if more than nmaster clients */ - mw = m->nmaster ? m->ww * m->mfact : 0; - tw = m->ww - mw; - - if (n - m->nmaster > 1) { - /* only one client */ - mx = (m->ww - mw) / 2; - tw = (m->ww - mw) / 2; - } - } - - oty = 0; - ety = 0; - for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) - if (i < m->nmaster) { - /* nmaster clients are stacked vertically, in the center - * of the screen */ - h = (m->wh - my) / (MIN(n, m->nmaster) - i); - resize(c, m->wx + mx, m->wy + my, mw - (2*c->bw), - h - (2*c->bw), 0); - my += HEIGHT(c); - } else { - /* stack clients are stacked vertically */ - if ((i - m->nmaster) % 2 ) { - h = (m->wh - ety) / ( (1 + n - i) / 2); - resize(c, m->wx, m->wy + ety, tw - (2*c->bw), - h - (2*c->bw), 0); - ety += HEIGHT(c); - } else { - h = (m->wh - oty) / ((1 + n - i) / 2); - resize(c, m->wx + mx + mw, m->wy + oty, - tw - (2*c->bw), h - (2*c->bw), 0); - oty += HEIGHT(c); - } - } -} - -void -centeredfloatingmaster(Monitor *m) -{ - unsigned int i, n, w, mh, mw, mx, mxo, my, myo, tx; - Client *c; - - /* count number of clients in the selected monitor */ - for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); - if (n == 0) - return; - - /* initialize nmaster area */ - if (n > m->nmaster) { - /* go mfact box in the center if more than nmaster clients */ - if (m->ww > m->wh) { - mw = m->nmaster ? m->ww * m->mfact : 0; - mh = m->nmaster ? m->wh * 0.9 : 0; - } else { - mh = m->nmaster ? m->wh * m->mfact : 0; - mw = m->nmaster ? m->ww * 0.9 : 0; - } - mx = mxo = (m->ww - mw) / 2; - my = myo = (m->wh - mh) / 2; - } else { - /* go fullscreen if all clients are in the master area */ - mh = m->wh; - mw = m->ww; - mx = mxo = 0; - my = myo = 0; - } - - for(i = tx = 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 */ - w = (mw + mxo - mx) / (MIN(n, m->nmaster) - i); - resize(c, m->wx + mx, m->wy + my, w - (2*c->bw), - mh - (2*c->bw), 0); - mx += WIDTH(c); - } else { - /* stack clients are stacked horizontally */ - w = (m->ww - tx) / (n - i); - resize(c, m->wx + tx, m->wy, w - (2*c->bw), - m->wh - (2*c->bw), 0); - tx += WIDTH(c); - } -} - -void -insertclient(Client *item, Client *insertItem, int after) { - Client *c; - if (item == NULL || insertItem == NULL || item == insertItem) return; - detach(insertItem); - if (!after && selmon->clients == item) { - attach(insertItem); - return; - } - if (after) { - c = item; - } else { - for (c = selmon->clients; c; c = c->next) { if (c->next == item) break; } - } - insertItem->next = c->next; - c->next = insertItem; -} - -void -inplacerotate(const Arg *arg) -{ - if(!selmon->sel || (selmon->sel->isfloating && !arg->f)) return; - - unsigned int selidx = 0, i = 0; - Client *c = NULL, *stail = NULL, *mhead = NULL, *mtail = NULL, *shead = NULL; - - // Determine positionings for insertclient - for (c = selmon->clients; c; c = c->next) { - if (ISVISIBLE(c) && !(c->isfloating)) { - if (selmon->sel == c) { selidx = i; } - if (i == selmon->nmaster - 1) { mtail = c; } - if (i == selmon->nmaster) { shead = c; } - if (mhead == NULL) { mhead = c; } - stail = c; - i++; - } - } - - // All clients rotate - if (arg->i == 2) insertclient(selmon->clients, stail, 0); - if (arg->i == -2) insertclient(stail, selmon->clients, 1); - // Stack xor master rotate - if (arg->i == -1 && selidx >= selmon->nmaster) insertclient(stail, shead, 1); - if (arg->i == 1 && selidx >= selmon->nmaster) insertclient(shead, stail, 0); - if (arg->i == -1 && selidx < selmon->nmaster) insertclient(mtail, mhead, 1); - if (arg->i == 1 && selidx < selmon->nmaster) insertclient(mhead, mtail, 0); - - // Restore focus position - i = 0; - for (c = selmon->clients; c; c = c->next) { - if (!ISVISIBLE(c) || (c->isfloating)) continue; - if (i == selidx) { focus(c); break; } - i++; - } - arrange(selmon); - focus(c); -} diff --git a/suckless/dwm/dwm_config_pulseaudio.h b/suckless/dwm/dwm_config_pulseaudio.h deleted file mode 100644 index 8e1d6f90..00000000 --- a/suckless/dwm/dwm_config_pulseaudio.h +++ /dev/null @@ -1,28 +0,0 @@ -/** - * dwmconfig.h - * Hardware multimedia keys - */ -/* Somewhere at the beginning of config.h include: - -#include - -/* Add somewhere in your constants definition section */ - -static const char *upvol[] = { "/usr/bin/pactl", "set-sink-volume", "0", "+5%", NULL }; -static const char *downvol[] = { "/usr/bin/pactl", "set-sink-volume", "0", "-5%", NULL }; -static const char *mutevol[] = { "/usr/bin/pactl", "set-sink-mute", "0", "toggle", NULL }; - -/* Add to keys[] array. With 0 as modifier, you are able to use the keys directly. */ -static Key keys[] = { - { 0, XF86XK_AudioLowerVolume, spawn, {.v = downvol } }, - { 0, XF86XK_AudioMute, spawn, {.v = mutevol } }, - { 0, XF86XK_AudioRaiseVolume, spawn, {.v = upvol } }, -}; - -/* If you have a small laptop keyboard or don't want to spring your fingers too far away. */ - -static Key keys[] = { - { MODKEY, XK_F11, spawn, {.v = downvol } }, - { MODKEY, XK_F9, spawn, {.v = mutevol } }, - { MODKEY, XK_F12, spawn, {.v = upvol } }, -}; diff --git a/suckless/dwm/fibonacci.c b/suckless/dwm/fibonacci.c deleted file mode 100644 index fce0a577..00000000 --- a/suckless/dwm/fibonacci.c +++ /dev/null @@ -1,66 +0,0 @@ -void -fibonacci(Monitor *mon, int s) { - unsigned int i, n, nx, ny, nw, nh; - Client *c; - - for(n = 0, c = nexttiled(mon->clients); c; c = nexttiled(c->next), n++); - if(n == 0) - return; - - nx = mon->wx; - ny = 0; - nw = mon->ww; - nh = mon->wh; - - for(i = 0, c = nexttiled(mon->clients); c; c = nexttiled(c->next)) { - if((i % 2 && nh / 2 > 2 * c->bw) - || (!(i % 2) && nw / 2 > 2 * c->bw)) { - if(i < n - 1) { - if(i % 2) - nh /= 2; - else - nw /= 2; - if((i % 4) == 2 && !s) - nx += nw; - else if((i % 4) == 3 && !s) - ny += nh; - } - if((i % 4) == 0) { - if(s) - ny += nh; - else - ny -= nh; - } - else if((i % 4) == 1) - nx += nw; - else if((i % 4) == 2) - ny += nh; - else if((i % 4) == 3) { - if(s) - nx += nw; - else - nx -= nw; - } - if(i == 0) - { - if(n != 1) - nw = mon->ww * mon->mfact; - ny = mon->wy; - } - else if(i == 1) - nw = mon->ww - nw; - i++; - } - resize(c, nx, ny, nw - 2 * c->bw, nh - 2 * c->bw, False); - } -} - -void -dwindle(Monitor *mon) { - fibonacci(mon, 1); -} - -void -spiral(Monitor *mon) { - fibonacci(mon, 0); -} diff --git a/suckless/dwm/flexipatch-finalizer.sh b/suckless/dwm/flexipatch-finalizer.sh new file mode 100755 index 00000000..18056716 --- /dev/null +++ b/suckless/dwm/flexipatch-finalizer.sh @@ -0,0 +1,345 @@ +#!/bin/bash + +KEEP_FILES=0 +ECHO_COMMANDS=0 +RUN_SCRIPT=0 +DIRECTORY=. +OUTPUT_DIRECTORY= +KEEP_GITFILES=0 +DEBUG=0 + +if [[ $# = 0 ]]; then + set -- '-h' +fi + +while (( $# )); do + case "$1" in + -d|--directory) + shift + DIRECTORY=$1 # source directory + shift + ;; + -o|--output) + shift + OUTPUT_DIRECTORY=$1 + shift + ;; + --debug) + shift + DEBUG=1 + ;; + -r|--run) + shift + RUN_SCRIPT=1 + ;; + -e|--echo) + shift + ECHO_COMMANDS=1 + ;; + -k|--keep) + shift + KEEP_FILES=1 + ;; + -g|--git) + shift + KEEP_GITFILES=1 + ;; + -h|--help) + shift + fmt=" %-31s%s\n" + + printf "%s" "Usage: $(basename ${BASH_SOURCE[0]}) [OPTION?]" + printf "\n" + printf "\nThis is a custom pre-processor designed to remove unused flexipatch patches and create a final build." + printf "\n\n" + printf "$fmt" "-r, --run" "include this flag to confirm that you really do want to run this script" + printf "\n" + printf "$fmt" "-d, --directory " "the flexipatch source directory to process (defaults to current directory)" + printf "$fmt" "-o, --output " "the output directory to store the processed files" + printf "$fmt" "-h, --help" "display this help section" + printf "$fmt" "-k, --keep" "keep temporary files and do not replace the original ones" + printf "$fmt" "-g, --git" "keep .git files" + printf "$fmt" "-e, --echo" "echo commands that will be run rather than running them" + printf "$fmt" " --debug" "prints additional debug information to stderr" + printf "\nWarning! This script alters and removes files within the source directory." + printf "\nWarning! This process is irreversible! Use with care. Do make a backup before running this." + printf "\n\n" + exit + ;; + *) + echo "Ignoring unknown argument ($1)" + shift + ;; + esac +done + +if [[ $RUN_SCRIPT = 0 ]]; then + echo "Re-run this command with the --run option to confirm that you really want to run this script." + echo "The changes this script makes are irreversible." + exit 1 +fi + +if [[ -z ${OUTPUT_DIRECTORY} ]]; then + echo "Output directory not specified, see -o" + exit 1 +fi + +DIRECTORY=$(readlink -f "${DIRECTORY}") +OUTPUT_DIRECTORY=$(readlink -f "${OUTPUT_DIRECTORY}") +if [[ $DIRECTORY != $OUTPUT_DIRECTORY ]]; then + mkdir -p "${OUTPUT_DIRECTORY}" + cp -r -f "${DIRECTORY}/." -t "${OUTPUT_DIRECTORY}" + DIRECTORY=${OUTPUT_DIRECTORY} +fi + +if [[ ! -e ${DIRECTORY}/patches.h ]]; then + printf "No patches.h file found. Make sure you run this script within a flexipatch source directory." + exit 1 +fi + + +FILES_TO_DELETE=$(find $DIRECTORY -name "*.c" -o -name "*.h" | awk -v DEBUG="$DEBUG" -v DIRECTORY="$DIRECTORY" ' +function istrue(f) { + ret = 0 + for ( i = 2; i in f; i++ ) { + if ( f[i] == "||" ) { + if ( ret == -1 ) { + ret = 0 + } else if ( ret == 1 ) { + break + } + continue + } else if ( f[i] == "&&" ) { + if ( ret == 0 ) { + ret = -1 + } + continue + } else if ( ret == -1 ) { + continue + } else if ( f[i] !~ /_(PATCH|LAYOUT)$/ ) { + ret = 1 + } else if ( f[i] ~ /^!/ ) { + ret = !patches[substr(f[i],2)] + } else { + ret = patches[f[i]] + } + } + + if ( ret == -1 ) { + ret = 0 + } + + return ret +} + +function schedule_delete(file) { + # Skip duplicates + for ( i = 1; i in files_to_delete; i++ ) { + if ( files_to_delete[i] == file) { + return + } + } + if (DEBUG) { + print "Scheduling file " file " for deletion." > "/dev/stderr" + } + files_to_delete[i] = file +} + +function is_flexipatch(patch) { + return patch ~ /_(PATCH|LAYOUT)$/ +} + +BEGIN { + # Read patches.h and store patch settings in the patches associative array + if (DEBUG) { + print "Reading file " DIRECTORY "/patches.h" > "/dev/stderr" + } + while (( getline line < (DIRECTORY"/patches.h") ) > 0 ) { + split(line,f) + if ( f[1] ~ /^#define$/ ) { + if ( f[3] == 0 || f[3] == 1 ) { + patches[f[2]] = f[3] + } else { + patches[f[2]] = istrue(f) + } + if (DEBUG) { + print "Found " f[2] " = " patches[f[2]] > "/dev/stderr" + } + } + } + files_to_delete[0] = "" +} + +{ + level = 0 + do_print[level] = 1 + has_printed[level] = 0 + condition[level] = "" + + while (( getline line < $0) > 0 ) { + split(line,f) + if ( f[1] ~ /^#if$/ ) { + level++; + do_print[level] = do_print[level-1] + has_printed[level] = 0 + condition[level] = f[2] + if ( do_print[level] ) { + if ( istrue(f) ) { + has_printed[level] = 1 + do_print[level] = 1 + } else { + do_print[level] = 0 + } + } + if ( is_flexipatch(condition[level]) ) { + continue + } + } else if ( f[1] ~ /^#ifdef$/ || f[1] ~ /^#ifndef$/ ) { + level++; + do_print[level] = do_print[level-1] + has_printed[level] = 0 + condition[level] = f[2] + if ( do_print[level] ) { + has_printed[level] = 1 + do_print[level] = 1 + } + if ( is_flexipatch(condition[level]) ) { + continue + } + } else if ( f[1] ~ /^#elif$/ ) { + if ( (!is_flexipatch(condition[level]) || has_printed[level] == 0) && do_print[level-1] == 1 ) { + if ( istrue(f) ) { + has_printed[level] = 1 + do_print[level] = 1 + } else { + do_print[level] = 0 + } + } else { + do_print[level] = 0 + } + if ( is_flexipatch(f[2]) ) { + continue + } + } else if ( f[1] ~ /^#else$/ ) { + if ( (!is_flexipatch(condition[level]) || has_printed[level] == 0) && do_print[level-1] == 1 ) { + has_printed[level] = 1 + do_print[level] = 1 + } else { + do_print[level] = 0 + } + if ( is_flexipatch(condition[level]) ) { + continue + } + } else if ( f[1] ~ /^#include$/ && f[2] ~ /^"/ && (do_print[level] == 0 || f[2] == "\"patches.h\"") ) { + dir = "" + if ( $0 ~ /\// ) { + dir = $0 + sub("/[^/]+$", "/", dir) + } + schedule_delete(dir substr(f[2], 2, length(f[2]) - 2)) + continue + } else if ( f[1] ~ /^#endif$/ ) { + if ( is_flexipatch(condition[level]) ) { + level-- + continue + } + level-- + } + + if ( do_print[level] ) { + print line > $0 ".~" + } + } +} + +END { + for ( i = 1; i in files_to_delete; i++ ) { + print files_to_delete[i] + } +} +') + +# Chmod and replace files +for FILE in $(find $DIRECTORY -name "*.~"); do + chmod --reference=${FILE%%.~} ${FILE} + if [[ $KEEP_FILES = 0 ]] || [[ $ECHO_COMMANDS = 1 ]]; then + if [[ $ECHO_COMMANDS = 1 ]]; then + echo "mv ${FILE} ${FILE%%.~}" + else + mv ${FILE} ${FILE%%.~} + fi + fi +done + +# Delete unnecessary files +if [[ $KEEP_FILES = 0 ]] || [[ $ECHO_COMMANDS = 1 ]]; then + + # Remove dwmc shell script if patch not enabled + if [[ -f ${DIRECTORY}/patch/dwmc ]] && [[ $(grep -cE '^#define DWMC_PATCH +0 *$' ${DIRECTORY}/patches.h) > 0 ]]; then + if [[ $ECHO_COMMANDS = 1 ]]; then + echo "rm ${DIRECTORY}/patch/dwmc" + echo "sed -r -i -e '/cp -f patch\/dwmc/d' \"${DIRECTORY}/Makefile\"" + else + rm "${DIRECTORY}/patch/dwmc" + sed -r -i -e '/cp -f patch\/dwmc/d' "${DIRECTORY}/Makefile" + fi + fi + + # Remove layoutmenu.sh shell script if patch not enabled + if [[ -f ${DIRECTORY}/patch/layoutmenu.sh ]] && [[ $(grep -cE '^#define BAR_LAYOUTMENU_PATCH +0 *$' ${DIRECTORY}/patches.h) > 0 ]]; then + if [[ $ECHO_COMMANDS = 1 ]]; then + echo "rm ${DIRECTORY}/patch/layoutmenu.sh" + else + rm "${DIRECTORY}/patch/layoutmenu.sh" + fi + fi + + for FILE in $FILES_TO_DELETE ${DIRECTORY}/patches.def.h; do + if [[ $ECHO_COMMANDS = 1 ]]; then + echo "rm $FILE" + else + rm "$FILE" + fi + done + + if [[ -f $DIRECTORY/README.md ]]; then + if [[ $ECHO_COMMANDS = 1 ]]; then + echo "rm $DIRECTORY/README.md" + else + rm $DIRECTORY/README.md + fi + fi + + if [[ $KEEP_GITFILES = 0 ]]; then + rm -rf $DIRECTORY/.git* + fi + + # Remove empty include files + INCLUDE_RE='*patch/*include.[hc]' + if [[ $ECHO_COMMANDS = 1 ]]; then + INCLUDE_RE='*patch/*include.[hc][.]~' + fi + for FILE in $(find $DIRECTORY -path "$INCLUDE_RE"); do + if [[ $(grep -c "#include " $FILE) = 0 ]]; then + if [[ $ECHO_COMMANDS = 1 ]]; then + echo "rm ${FILE%%.~}" + else + rm "$FILE" + fi + + for LINE in $(grep -Ern "#include \"patch/$(basename ${FILE%%.~})\"" $DIRECTORY | grep -v '.~:' | awk -F":" '{print $1 ":" $2 }'); do + INCFILE=$(echo $LINE | cut -d":" -f1) + LINE_NO=$(echo $LINE | cut -d":" -f2) + if [[ $ECHO_COMMANDS = 1 ]]; then + echo "sed -i \"${LINE_NO}d\" ${INCFILE}" + else + sed -i "${LINE_NO}d" ${INCFILE} + fi + done + fi + + done +fi + +# Clean up the Makefile +sed -r -i -e 's/ patches.h$//' -e '/^patches.h:$/{N;N;d;}' "${DIRECTORY}/Makefile" diff --git a/suckless/dwm/keybind.h b/suckless/dwm/keybind.h new file mode 100644 index 00000000..d87390fc --- /dev/null +++ b/suckless/dwm/keybind.h @@ -0,0 +1,132 @@ +#include + +/* key definitions */ +#define MODKEY Mod4Mask +#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} }, + +/* helper for spawning shell commands in the pre dwm-5.0 fashion */ +#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } +static char dmenumon[2] = "0"; +static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-z", "1900", "-x", "10", "-y", "10"}; +static const char *termcmd[] = { "/usr/local/bin/st", NULL }; +static const char *upvol[] = { "/home/yigit/.scripts/pacontrol.sh", "up", NULL }; +static const char *downvol[] = { "/home/yigit/.scripts/pacontrol.sh", "down", NULL }; +static const char *mutevol[] = { "/home/yigit/.scripts/pacontrol.sh", "togglemute", NULL }; + +static const char *upbright[] = {"/usr/bin/xbacklight","-inc","10",NULL}; +static const char *downbright[] = {"/usr/bin/xbacklight","-dec","10",NULL}; + +static const char *lock[] = {"/usr/bin/betterlockscreen","-l","-t","Stay the fuck out!",NULL}; +static const char *clipmenu[] = {"/usr/bin/clipmenu","-i",NULL}; +static const char *play[] = {"/usr/bin/playerctl","play-pause",NULL}; +static const char *prev[] = {"/usr/bin/playerctl","previous",NULL}; +static const char *next[] = {"/usr/bin/playerctl","next",NULL}; +static const char *outmenu[] = {"/home/yigit/.scripts/dmenu-logout"}; + +static const char *notification_off[] = {"/home/yigit/.scripts/dunst_toggle.sh","-s",NULL}; +static const char *notification_on[] = {"/home/yigit/.scripts/dunst_toggle.sh", "-e",NULL}; + +static const char *bwmenu[] = {"/usr/bin/bwmenu", "--auto-lock", "-1", NULL}; +static const char *network_manager[] = {"/home/yigit/.scripts/networkmanager_dmenu"}; + +static const char *trackpad[] = {"/home/yigit/.scripts/toggle_touchpad.sh"}; + +static const char *kdeconnect[] = {"/home/yigit/.local/bin/dmenu_kdeconnect.sh", NULL}; + +static const char *bluetooth[] = {"/home/yigit/.scripts/dmenu-bluetooth", NULL}; + +static const char *screenshot[] = { "scrot","-d","3", "%Y-%m-%d-%s_$wx$h.jpg", "-e","xclip -selection clipboard -t image/jpg < $f; mv $f ~/Pictures/Screenshots/;dunstify --icon='/home/yigit/.icons/Numix-Circle/48/apps/camera.svg' -a 'SNAP' 'Screenshot taken'", NULL }; +static const char *windowshot[] = { "scrot", "-u", "-d","3", "%Y-%m-%d-%s_$wx$h.jpg", "-e","xclip -selection clipboard -t image/jpg < $f; mv $f ~/Pictures/Screenshots/;dunstify --icon='/home/yigit/.icons/Numix-Circle/48/apps/camera.svg' -a 'SNAP' 'Screenshot taken'", NULL }; + +/* commands */ +static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_d, spawn, {.v = dmenucmd } }, + { MODKEY, XK_p, spawn, {.v = bwmenu } }, + { MODKEY, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_b, togglebar, {0} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_n, spawn, {.v = notification_off} }, + { MODKEY|ShiftMask, XK_n, spawn, {.v = notification_on } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, + { MODKEY, XK_s, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, + { MODKEY|ShiftMask, XK_Return, zoom, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY, XK_q, killclient, {0} }, + { MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } }, + { MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } }, + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, /*tiled*/ + { MODKEY|Mod1Mask, XK_f, setlayout, {.v = &layouts[1]} }, /*Spiral*/ + { MODKEY|Mod1Mask, XK_g, setlayout, {.v = &layouts[2]} }, /*Grid*/ + { MODKEY|Mod1Mask, XK_c, setlayout, {.v = &layouts[3]} }, /*center*/ + { MODKEY, XK_m, setlayout, {.v = &layouts[5]} }, /*monocle*/ + { MODKEY|ShiftMask, XK_m, setlayout, {.v = &layouts[6]} }, /*Deck*/ + // { MODKEY, XK_s, togglefloating, {0} }, [>float<] + // { MODKEY, XK_f, togglefullscr, {0} }, [>Fullscreen<] + { MODKEY|Mod1Mask, XK_comma, cyclelayout, {.i = -1 } }, /*Ciclar layouts*/ + { MODKEY|Mod1Mask, XK_period, cyclelayout, {.i = +1 } }, /*Ciclar layouts*/ + { MODKEY, XK_a, view, {.ui = ~0 } }, + { MODKEY|ShiftMask, XK_a, 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_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) + TAGKEYS( XK_0, 9) + { MODKEY|ShiftMask, XK_q, spawn, {.v = outmenu} }, + { MODKEY|ShiftMask, XK_t, spawn, {.v = trackpad} }, + { MODKEY, XK_x, spawn, {.v = lock } }, + { MODKEY, XK_c, spawn, {.v = clipmenu } }, + { MODKEY|ShiftMask, XK_p, spawn, {.v = kdeconnect } }, + { MODKEY|ShiftMask, XK_b, spawn, {.v = bluetooth } }, + { MODKEY|Mod1Mask, XK_n, spawn, {.v = network_manager} }, /*Spiral*/ + { 0, XF86XK_AudioLowerVolume, spawn, {.v = downvol } }, + { 0, XF86XK_MonBrightnessUp, spawn, {.v = upbright } }, + { 0, XF86XK_MonBrightnessDown, spawn, {.v = downbright } }, + { 0, XF86XK_AudioMute, spawn, {.v = mutevol } }, + { 0, XF86XK_AudioRaiseVolume, spawn, {.v = upvol } }, + { 0, XF86XK_AudioPrev, spawn, {.v = prev } }, + { 0, XF86XK_AudioPlay, spawn, {.v = play } }, + { 0, XF86XK_AudioNext, spawn, {.v = next } }, + { 0, XK_Print, spawn, {.v = screenshot } }, + { MODKEY, XK_Print, spawn, {.v = windowshot } }, + +}; + +/* button definitions */ +/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ + +static Button buttons[] = { + /* click event mask button function argument */ + { ClkLtSymbol, 0, Button1, setlayout, {0} }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { 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} }, + { ClkStatusText, 0, Button1, sigdwmblocks, {.i = 1 } }, + { ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2 } }, + { ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3 } }, + { ClkLtSymbol, 0, Button3, layoutmenu, {0} }, +}; + diff --git a/suckless/dwm/layouts.c b/suckless/dwm/layouts.c deleted file mode 100644 index d26acf34..00000000 --- a/suckless/dwm/layouts.c +++ /dev/null @@ -1,27 +0,0 @@ -void -grid(Monitor *m) { - unsigned int i, n, cx, cy, cw, ch, aw, ah, cols, rows; - Client *c; - - for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) - 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 / (rows ? rows : 1); - cw = m->ww / (cols ? cols : 1); - for(i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) { - cx = m->wx + (i / rows) * cw; - cy = m->wy + (i % rows) * ch; - /* adjust height/width of last row/column's windows */ - ah = ((i + 1) % rows == 0) ? m->wh - ch * rows : 0; - aw = (i >= rows * (cols - 1)) ? m->ww - cw * cols : 0; - resize(c, cx, cy, cw - 2 * c->bw + aw, ch - 2 * c->bw + ah, False); - i++; - } -} diff --git a/suckless/dwm/patch/aspectresize.c b/suckless/dwm/patch/aspectresize.c new file mode 100644 index 00000000..73a03425 --- /dev/null +++ b/suckless/dwm/patch/aspectresize.c @@ -0,0 +1,24 @@ +void +aspectresize(const Arg *arg) +{ + /* only floating windows can be moved */ + Client *c; + c = selmon->sel; + float ratio; + int w, h,nw, nh; + + if (!c || !arg) + return; + if (selmon->lt[selmon->sellt]->arrange && !c->isfloating) + return; + + ratio = (float)c->w / (float)c->h; + h = arg->i; + w = (int)(ratio * h); + + nw = c->w + w; + nh = c->h + h; + + XRaiseWindow(dpy, c->win); + resize(c, c->x, c->y, nw, nh, True); +} \ No newline at end of file diff --git a/suckless/dwm/patch/aspectresize.h b/suckless/dwm/patch/aspectresize.h new file mode 100644 index 00000000..ad0d0546 --- /dev/null +++ b/suckless/dwm/patch/aspectresize.h @@ -0,0 +1 @@ +static void aspectresize(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/attachx.c b/suckless/dwm/patch/attachx.c new file mode 100644 index 00000000..a9b99b62 --- /dev/null +++ b/suckless/dwm/patch/attachx.c @@ -0,0 +1,42 @@ +void +attachx(Client *c) +{ + #if ATTACHABOVE_PATCH + Client *at; + if (!(c->mon->sel == NULL || c->mon->sel == c->mon->clients || c->mon->sel->isfloating)) { + for (at = c->mon->clients; at->next != c->mon->sel; at = at->next); + c->next = at->next; + at->next = c; + return; + } + #elif ATTACHASIDE_PATCH + Client *at; + unsigned int n; + + for (at = c->mon->clients, n = 0; at; at = at->next) + if (!at->isfloating && ISVISIBLEONTAG(at, c->tags)) + if (++n >= c->mon->nmaster) + break; + + if (at && c->mon->nmaster) { + c->next = at->next; + at->next = c; + return; + } + #elif ATTACHBELOW_PATCH + if (!(c->mon->sel == NULL || c->mon->sel == c || c->mon->sel->isfloating)) { + c->next = c->mon->sel->next; + c->mon->sel->next = c; + return; + } + #elif ATTACHBOTTOM_PATCH + Client *at; + for (at = c->mon->clients; at && at->next; at = at->next); + if (at) { + at->next = c; + c->next = NULL; + return; + } + #endif + attach(c); // master (default) +} diff --git a/suckless/dwm/patch/attachx.h b/suckless/dwm/patch/attachx.h new file mode 100644 index 00000000..46a8c392 --- /dev/null +++ b/suckless/dwm/patch/attachx.h @@ -0,0 +1 @@ +static void attachx(Client *c); \ No newline at end of file diff --git a/suckless/dwm/patch/autostart.c b/suckless/dwm/patch/autostart.c new file mode 100644 index 00000000..b829c593 --- /dev/null +++ b/suckless/dwm/patch/autostart.c @@ -0,0 +1,83 @@ +void +runautostart(void) +{ + char *pathpfx; + char *path; + char *xdgdatahome; + char *home; + + if ((home = getenv("HOME")) == NULL) + /* this is almost impossible */ + return; + + /* if $XDG_DATA_HOME is defined, use $XDG_DATA_HOME/dwm, + * otherwise use ~/.local/share/dwm as autostart script directory + */ + if ((xdgdatahome = getenv("XDG_DATA_HOME")) != NULL) { + /* space for path segments, separators and nul */ + if ((pathpfx = malloc(strlen(xdgdatahome) + strlen(dwmdir) + 2)) == NULL) + return; + + if (sprintf(pathpfx, "%s/%s", xdgdatahome, dwmdir) <= 0) { + free(pathpfx); + return; + } + } else { + /* space for path segments, separators and nul */ + if ((pathpfx = malloc(strlen(home) + strlen(localshare) + strlen(dwmdir) + 3)) == NULL) + return; + + if (sprintf(pathpfx, "%s/%s/%s", home, localshare, dwmdir) < 0) { + free(pathpfx); + return; + } + } + + /* check if the autostart script directory exists */ + struct stat sb; + + if (! (stat(pathpfx, &sb) == 0 && S_ISDIR(sb.st_mode))) { + /* the XDG conformant path does not exist or are not directories + * so we try ~/.dwm instead + */ + if (realloc(pathpfx, strlen(home) + strlen(dwmdir) + 3) == NULL) { + free(pathpfx); + return; + } + + if (sprintf(pathpfx, "%s/.%s", home, dwmdir) <= 0) { + free(pathpfx); + return; + } + } + + /* try the blocking script first */ + if ((path = malloc(strlen(pathpfx) + strlen(autostartblocksh) + 2)) == NULL) { + free(pathpfx); + return; + } else + if (sprintf(path, "%s/%s", pathpfx, autostartblocksh) <= 0) { + free(path); + free(pathpfx); + } + + if (access(path, X_OK) == 0) + system(path); + + /* now the non-blocking script */ + if ((path = realloc(path, strlen(pathpfx) + strlen(autostartsh) + 4)) == NULL) { + free(pathpfx); + free(path); + return; + } else + if (sprintf(path, "%s/%s", pathpfx, autostartsh) <= 0) { + free(path); + free(pathpfx); + } + + if (access(path, X_OK) == 0) { + system(strcat(path, " &")); + free(pathpfx); + free(path); + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/autostart.h b/suckless/dwm/patch/autostart.h new file mode 100644 index 00000000..299eaef4 --- /dev/null +++ b/suckless/dwm/patch/autostart.h @@ -0,0 +1 @@ +static void runautostart(void); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_alpha.c b/suckless/dwm/patch/bar_alpha.c new file mode 100644 index 00000000..d86bc1d4 --- /dev/null +++ b/suckless/dwm/patch/bar_alpha.c @@ -0,0 +1,42 @@ + +static int useargb = 0; +static Visual *visual; +static int depth; +static Colormap cmap; + +void +xinitvisual() +{ + XVisualInfo *infos; + XRenderPictFormat *fmt; + int nitems; + int i; + + XVisualInfo tpl = { + .screen = screen, + .depth = 32, + .class = TrueColor + }; + long masks = VisualScreenMask | VisualDepthMask | VisualClassMask; + + infos = XGetVisualInfo(dpy, masks, &tpl, &nitems); + visual = NULL; + for (i = 0; i < nitems; i ++) { + fmt = XRenderFindVisualFormat(dpy, infos[i].visual); + if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) { + visual = infos[i].visual; + depth = infos[i].depth; + cmap = XCreateColormap(dpy, root, visual, AllocNone); + useargb = 1; + break; + } + } + + XFree(infos); + + if (!visual) { + visual = DefaultVisual(dpy, screen); + depth = DefaultDepth(dpy, screen); + cmap = DefaultColormap(dpy, screen); + } +} diff --git a/suckless/dwm/patch/bar_alpha.h b/suckless/dwm/patch/bar_alpha.h new file mode 100644 index 00000000..3c81522c --- /dev/null +++ b/suckless/dwm/patch/bar_alpha.h @@ -0,0 +1,3 @@ +#define OPAQUE 0xffU + +static void xinitvisual(); diff --git a/suckless/dwm/patch/bar_alternativetags.c b/suckless/dwm/patch/bar_alternativetags.c new file mode 100644 index 00000000..3c329bc5 --- /dev/null +++ b/suckless/dwm/patch/bar_alternativetags.c @@ -0,0 +1,6 @@ +void +togglealttag() +{ + selmon->alttag = !selmon->alttag; + drawbar(selmon); +} \ No newline at end of file diff --git a/suckless/dwm/patch/bar_alternativetags.h b/suckless/dwm/patch/bar_alternativetags.h new file mode 100644 index 00000000..2c130f30 --- /dev/null +++ b/suckless/dwm/patch/bar_alternativetags.h @@ -0,0 +1 @@ +static void togglealttag(); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_anybar.c b/suckless/dwm/patch/bar_anybar.c new file mode 100644 index 00000000..05b2513f --- /dev/null +++ b/suckless/dwm/patch/bar_anybar.c @@ -0,0 +1,82 @@ +void +managealtbar(Window win, XWindowAttributes *wa) +{ + Monitor *m; + Bar *bar; + int i; + if (!(m = recttomon(wa->x, wa->y, wa->width, wa->height))) + return; + for (i = 0, bar = m->bar; bar && bar->win && bar->next; bar = bar->next, ++i); // find last bar + if (!bar) { + bar = m->bar = ecalloc(1, sizeof(Bar)); + bar->topbar = topbar; + } else if (bar && bar->win) { + bar->next = ecalloc(1, sizeof(Bar)); + bar->next->topbar = !bar->topbar; + bar = bar->next; + } + bar->external = 1; + bar->showbar = 1; + bar->mon = m; + bar->idx = i; + bar->borderpx = 0; + bar->win = win; + bar->bh = wa->height; + updatebarpos(m); + arrange(m); + XSelectInput(dpy, win, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); + XMapWindow(dpy, win); + XMoveResizeWindow(dpy, bar->win, bar->bx, -bar->by, wa->width, bar->bh); + arrange(selmon); + XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &win, 1); +} + +void +spawnbar() +{ + if (*altbarcmd) + system(altbarcmd); +} + +void +unmanagealtbar(Window w) +{ + Monitor *m = wintomon(w); + Bar *bar; + + if (!m) + return; + + for (bar = m->bar; bar && bar->win; bar = bar->next) + if (bar->win == w) { + bar->win = 0; + bar->by = 0; + bar->bh = 0; + break; + } + updatebarpos(m); + arrange(m); +} + +int +wmclasscontains(Window win, const char *class, const char *name) +{ + XClassHint ch = { NULL, NULL }; + int res = 1; + + if (XGetClassHint(dpy, win, &ch)) { + if (ch.res_name && strstr(ch.res_name, name) == NULL) + res = 0; + if (ch.res_class && strstr(ch.res_class, class) == NULL) + res = 0; + } else + res = 0; + + if (ch.res_class) + XFree(ch.res_class); + if (ch.res_name) + XFree(ch.res_name); + + return res; +} \ No newline at end of file diff --git a/suckless/dwm/patch/bar_anybar.h b/suckless/dwm/patch/bar_anybar.h new file mode 100644 index 00000000..99f439ac --- /dev/null +++ b/suckless/dwm/patch/bar_anybar.h @@ -0,0 +1,4 @@ +static void managealtbar(Window win, XWindowAttributes *wa); +static void spawnbar(); +static void unmanagealtbar(Window w); +static int wmclasscontains(Window win, const char *class, const char *name); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_awesomebar.c b/suckless/dwm/patch/bar_awesomebar.c new file mode 100644 index 00000000..ec5fa55a --- /dev/null +++ b/suckless/dwm/patch/bar_awesomebar.c @@ -0,0 +1,79 @@ +int +width_awesomebar(Bar *bar, BarArg *a) +{ + return a->w; +} + +int +draw_awesomebar(Bar *bar, BarArg *a) +{ + int n = 0, scm, remainder = 0, tabw, pad; + unsigned int i; + #if BAR_TITLE_LEFT_PAD_PATCH && BAR_TITLE_RIGHT_PAD_PATCH + int x = a->x + lrpad / 2, w = a->w - lrpad; + #elif BAR_TITLE_LEFT_PAD_PATCH + int x = a->x + lrpad / 2, w = a->w - lrpad / 2; + #elif BAR_TITLE_RIGHT_PAD_PATCH + int x = a->x, w = a->w - lrpad / 2; + #else + int x = a->x, w = a->w; + #endif // BAR_TITLE_LEFT_PAD_PATCH | BAR_TITLE_RIGHT_PAD_PATCH + + Client *c; + for (c = bar->mon->clients; c; c = c->next) + if (ISVISIBLE(c)) + n++; + + if (n > 0) { + remainder = w % n; + tabw = w / n; + for (i = 0, c = bar->mon->clients; c; c = c->next, i++) { + if (!ISVISIBLE(c)) + continue; + if (bar->mon->sel == c) + scm = SchemeTitleSel; + else if (HIDDEN(c)) + scm = SchemeHid; + else + scm = SchemeTitleNorm; + + pad = lrpad / 2; + #if BAR_CENTEREDWINDOWNAME_PATCH + if (TEXTW(c->name) < tabw) + pad = (tabw - TEXTW(c->name) + lrpad) / 2; + #endif // BAR_CENTEREDWINDOWNAME_PATCH + + drw_setscheme(drw, scheme[scm]); + drw_text(drw, x, a->y, tabw + (i < remainder ? 1 : 0), a->h, pad, c->name, 0, False); + drawstateindicator(c->mon, c, 1, x, a->y, tabw + (i < remainder ? 1 : 0), a->h, 0, 0, c->isfixed); + x += tabw + (i < remainder ? 1 : 0); + } + } + return n; +} + +int +click_awesomebar(Bar *bar, Arg *arg, BarArg *a) +{ + int x = 0, n = 0; + Client *c; + + for (c = bar->mon->clients; c; c = c->next) + if (ISVISIBLE(c)) + n++; + + c = bar->mon->clients; + + do { + if (!c || !ISVISIBLE(c)) + continue; + else + x += (1.0 / (double)n) * a->w; + } while (c && a->x > x && (c = c->next)); + + if (c) { + arg->v = c; + return ClkWinTitle; + } + return -1; +} diff --git a/suckless/dwm/patch/bar_awesomebar.h b/suckless/dwm/patch/bar_awesomebar.h new file mode 100644 index 00000000..25bd98f1 --- /dev/null +++ b/suckless/dwm/patch/bar_awesomebar.h @@ -0,0 +1,3 @@ +static int width_awesomebar(Bar *bar, BarArg *a); +static int draw_awesomebar(Bar *bar, BarArg *a); +static int click_awesomebar(Bar *bar, Arg *arg, BarArg *a); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_dwmblocks.c b/suckless/dwm/patch/bar_dwmblocks.c new file mode 100644 index 00000000..442b0bcd --- /dev/null +++ b/suckless/dwm/patch/bar_dwmblocks.c @@ -0,0 +1,31 @@ +static int dwmblockssig; +pid_t dwmblockspid = 0; + +int +getdwmblockspid() +{ + char buf[16]; + FILE *fp = popen("pidof -s dwmblocks", "r"); + if (fgets(buf, sizeof(buf), fp)); + pid_t pid = strtoul(buf, NULL, 10); + pclose(fp); + dwmblockspid = pid; + return pid != 0 ? 0 : -1; +} + +void +sigdwmblocks(const Arg *arg) +{ + union sigval sv; + sv.sival_int = (dwmblockssig << 8) | arg->i; + if (!dwmblockspid) + if (getdwmblockspid() == -1) + return; + + if (sigqueue(dwmblockspid, SIGUSR1, sv) == -1) { + if (errno == ESRCH) { + if (!getdwmblockspid()) + sigqueue(dwmblockspid, SIGUSR1, sv); + } + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/bar_dwmblocks.h b/suckless/dwm/patch/bar_dwmblocks.h new file mode 100644 index 00000000..f08f1d56 --- /dev/null +++ b/suckless/dwm/patch/bar_dwmblocks.h @@ -0,0 +1,2 @@ +static int getdwmblockspid(); +static void sigdwmblocks(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_ewmhtags.c b/suckless/dwm/patch/bar_ewmhtags.c new file mode 100644 index 00000000..99774c95 --- /dev/null +++ b/suckless/dwm/patch/bar_ewmhtags.c @@ -0,0 +1,52 @@ +void +setcurrentdesktop(void) +{ + long data[] = { 0 }; + XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); +} + +void +setdesktopnames(void) +{ + int i; + XTextProperty text; + char *tags[NUMTAGS]; + for (i = 0; i < NUMTAGS; i++) + tags[i] = tagicon(selmon, i); + Xutf8TextListToTextProperty(dpy, tags, NUMTAGS, XUTF8StringStyle, &text); + XSetTextProperty(dpy, root, &text, netatom[NetDesktopNames]); +} + +void +setfloatinghint(Client *c) +{ + Atom target = XInternAtom(dpy, "_IS_FLOATING", 0); + unsigned int floating[1] = {c->isfloating}; + XChangeProperty(dpy, c->win, target, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)floating, 1); +} + +void +setnumdesktops(void) +{ + long data[] = { NUMTAGS }; + XChangeProperty(dpy, root, netatom[NetNumberOfDesktops], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); +} + +void +setviewport(void) +{ + long data[] = { 0, 0 }; + XChangeProperty(dpy, root, netatom[NetDesktopViewport], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 2); +} + +void +updatecurrentdesktop(void) +{ + long rawdata[] = { selmon->tagset[selmon->seltags] }; + int i = 0; + while (*rawdata >> (i + 1)) { + i++; + } + long data[] = { i }; + XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); +} \ No newline at end of file diff --git a/suckless/dwm/patch/bar_ewmhtags.h b/suckless/dwm/patch/bar_ewmhtags.h new file mode 100644 index 00000000..959ab75a --- /dev/null +++ b/suckless/dwm/patch/bar_ewmhtags.h @@ -0,0 +1,6 @@ +static void setcurrentdesktop(void); +static void setdesktopnames(void); +static void setfloatinghint(Client *c); +static void setnumdesktops(void); +static void setviewport(void); +static void updatecurrentdesktop(void); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_fancybar.c b/suckless/dwm/patch/bar_fancybar.c new file mode 100644 index 00000000..0222ca74 --- /dev/null +++ b/suckless/dwm/patch/bar_fancybar.c @@ -0,0 +1,70 @@ +int +width_fancybar(Bar *bar, BarArg *a) +{ + return a->w; +} + +int +draw_fancybar(Bar *bar, BarArg *a) +{ + int ftw, mw, ew = 0, n = 0; + unsigned int i; + Client *c; + Monitor *m = bar->mon; + + #if BAR_TITLE_LEFT_PAD_PATCH && BAR_TITLE_RIGHT_PAD_PATCH + int x = a->x + lrpad / 2, w = a->w - lrpad; + #elif BAR_TITLE_LEFT_PAD_PATCH + int x = a->x + lrpad / 2, w = a->w - lrpad / 2; + #elif BAR_TITLE_RIGHT_PAD_PATCH + int x = a->x, w = a->w - lrpad / 2; + #else + int x = a->x, w = a->w; + #endif // BAR_TITLE_LEFT_PAD_PATCH | BAR_TITLE_RIGHT_PAD_PATCH + + for (c = m->clients; c; c = c->next) { + if (ISVISIBLE(c)) + n++; + } + + if (n > 0) { + ftw = TEXTW(m->sel->name); + mw = (ftw >= w || n == 1) ? 0 : (w - ftw) / (n - 1); + + i = 0; + + for (c = m->clients; c; c = c->next) { + if (!ISVISIBLE(c) || c == m->sel) + continue; + ftw = TEXTW(c->name); + if (ftw < mw) + ew += (mw - ftw); + else + i++; + } + + if (i > 0) + mw += ew / i; + + for (c = m->clients; c; c = c->next) { + if (!ISVISIBLE(c)) + continue; + ftw = MIN(m->sel == c ? w : mw, TEXTW(c->name)); + drw_setscheme(drw, scheme[m->sel == c ? SchemeTitleSel : SchemeTitleNorm]); + if (ftw > 0) /* trap special handling of 0 in drw_text */ + drw_text(drw, x, a->y, ftw, a->h, lrpad / 2, c->name, 0, False); + drawstateindicator(c->mon, c, 1, x, a->y, ftw, a->h, 0, 0, c->isfixed); + x += ftw; + w -= ftw; + } + } + return n; +} + +int +click_fancybar(Bar *bar, Arg *arg, BarArg *a) +{ + return ClkWinTitle; +} + + diff --git a/suckless/dwm/patch/bar_fancybar.h b/suckless/dwm/patch/bar_fancybar.h new file mode 100644 index 00000000..b4f81749 --- /dev/null +++ b/suckless/dwm/patch/bar_fancybar.h @@ -0,0 +1,3 @@ +static int width_fancybar(Bar *bar, BarArg *a); +static int draw_fancybar(Bar *bar, BarArg *a); +static int click_fancybar(Bar *bar, Arg *arg, BarArg *a); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_flexwintitle.c b/suckless/dwm/patch/bar_flexwintitle.c new file mode 100644 index 00000000..f7da241b --- /dev/null +++ b/suckless/dwm/patch/bar_flexwintitle.c @@ -0,0 +1,436 @@ +/* Flexwintitle properties, you can override these in your config.h if you want. */ +#ifndef FLEXWINTITLE_BORDERS +#define FLEXWINTITLE_BORDERS 1 // 0 = off, 1 = on +#endif +#ifndef FLEXWINTITLE_SHOWFLOATING +#define FLEXWINTITLE_SHOWFLOATING 0 // whether to show titles for floating windows, hidden clients are always shown +#endif +#ifndef FLEXWINTITLE_MASTERWEIGHT +#define FLEXWINTITLE_MASTERWEIGHT 9 // master weight compared to stack, hidden and floating window titles +#endif +#ifndef FLEXWINTITLE_STACKWEIGHT +#define FLEXWINTITLE_STACKWEIGHT 3 // stack weight compared to master, hidden and floating window titles +#endif +#ifndef FLEXWINTITLE_HIDDENWEIGHT +#define FLEXWINTITLE_HIDDENWEIGHT 1 // hidden window title weight +#endif +#ifndef FLEXWINTITLE_FLOATWEIGHT +#define FLEXWINTITLE_FLOATWEIGHT 1 // floating window title weight, set to 0 to not show floating windows +#endif + +#define SCHEMEFOR(c) getschemefor(m, c, groupactive == c) + +enum { GRP_NOSELECTION, GRP_MASTER, GRP_STACK1, GRP_STACK2, GRP_FLOAT, GRP_HIDDEN }; + +int +width_flexwintitle(Bar *bar, BarArg *a) +{ + return a->w; +} + +int +draw_flexwintitle(Bar *bar, BarArg *a) +{ + drw_rect(drw, a->x, a->y, a->w, a->h, 1, 1); + return flextitlecalculate(bar->mon, a->x, a->w, -1, flextitledraw, NULL, a); +} + +int +click_flexwintitle(Bar *bar, Arg *arg, BarArg *a) +{ + flextitlecalculate(bar->mon, 0, a->w, a->x, flextitleclick, arg, a); + return ClkWinTitle; +} + +Client * +flextitledrawarea(Monitor *m, Client *c, int x, int r, int w, int max_clients, int scheme, int draw_tiled, int draw_hidden, int draw_floating, + int passx, void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg), Arg *arg, BarArg *barg) +{ + int i; + for (i = 0; c && i < max_clients; c = c->next) { + if ( + ISVISIBLE(c) && + ( + (draw_tiled && !c->isfloating && !HIDDEN(c)) || + (draw_floating && c->isfloating && !HIDDEN(c)) || + (draw_hidden && HIDDEN(c)) + ) + ) { + tabfn(m, c, passx, x, w + (i < r ? 1 : 0), scheme, arg, barg); + x += w + (i < r ? 1 : 0); + i++; + } + } + return c; +} + +int +getschemefor(Monitor *m, int group, int activegroup) +{ + switch (group) { + case GRP_NOSELECTION: + case GRP_MASTER: + case GRP_STACK1: + case GRP_STACK2: + #if BSTACK_LAYOUT + if (m->lt[m->sellt]->arrange == &bstack) + return (activegroup ? SchemeFlexActLTR : SchemeFlexInaLTR); + #endif // BSTACK_LAYOUT + #if BSTACKHORIZ_LAYOUT + if (m->lt[m->sellt]->arrange == &bstackhoriz) { + if (group == GRP_MASTER) + return (activegroup ? SchemeFlexActLTR : SchemeFlexInaLTR); + else + return (activegroup ? SchemeFlexActTTB : SchemeFlexInaTTB); + } + #endif // BSTACKHORIZ_LAYOUT + #if CENTEREDMASTER_LAYOUT + if (m->lt[m->sellt]->arrange == ¢eredmaster) + return (activegroup ? SchemeFlexActTTB : SchemeFlexInaTTB); + #endif // CENTEREDMASTER_LAYOUT + #if CENTEREDFLOATINGMASTER_LAYOUT + if (m->lt[m->sellt]->arrange == ¢eredfloatingmaster) + return (activegroup ? SchemeFlexActLTR : SchemeFlexInaLTR); + #endif // CENTEREDFLOATINGMASTER_LAYOUT + #if COLUMNS_LAYOUT + if (m->lt[m->sellt]->arrange == &col) { + if (group == GRP_MASTER) + return (activegroup ? SchemeFlexActLTR : SchemeFlexInaLTR); + else + return (activegroup ? SchemeFlexActTTB : SchemeFlexInaTTB); + } + #endif // COLUMNS_LAYOUT + #if DECK_LAYOUT + if (m->lt[m->sellt]->arrange == &deck) { + if (group == GRP_MASTER) + return (activegroup ? SchemeFlexActTTB : SchemeFlexInaTTB); + else + return (activegroup ? SchemeFlexActMONO : SchemeFlexInaMONO); + } + #endif // DECK_LAYOUT + #if FIBONACCI_DWINDLE_LAYOUT + if (m->lt[m->sellt]->arrange == &dwindle) + return (activegroup ? SchemeFlexActDWDL : SchemeFlexInaDWDL); + #endif // FIBONACCI_DWINDLE_LAYOUT + #if FIBONACCI_SPIRAL_LAYOUT + if (m->lt[m->sellt]->arrange == &spiral) + return (activegroup ? SchemeFlexActSPRL : SchemeFlexInaSPRL); + #endif // FIBONACCI_SPIRAL_LAYOUT + #if FLEXTILE_DELUXE_LAYOUT + if (m->lt[m->sellt]->arrange == &flextile) + return (activegroup ? SchemeFlexActTTB + m->ltaxis[group] : SchemeFlexInaTTB + m->ltaxis[group]); + #endif // FLEXTILE_DELUXE_LAYOUT + #if GAPPLESSGRID_LAYOUT + if (m->lt[m->sellt]->arrange == &gaplessgrid) + return (activegroup ? SchemeFlexActGRID : SchemeFlexInaGRID); + #endif // GAPPLESSGRID_LAYOUT + #if GRIDMODE_LAYOUT + if (m->lt[m->sellt]->arrange == &grid) + return (activegroup ? SchemeFlexActGRDM : SchemeFlexInaGRDM); + #endif // GRIDMODE_LAYOUT + #if HORIZGRID_LAYOUT + if (m->lt[m->sellt]->arrange == &horizgrid) + return (activegroup ? SchemeFlexActHGRD : SchemeFlexInaHGRD); + #endif // HORIZGRID_LAYOUT + #if NROWGRID_LAYOUT + if (m->lt[m->sellt]->arrange == &nrowgrid) + return (activegroup ? SchemeFlexActGRD1 : SchemeFlexInaGRD1); + #endif // NROWGRID_LAYOUT + #if TILE_LAYOUT + if (m->lt[m->sellt]->arrange == &tile) + return (activegroup ? SchemeFlexActTTB : SchemeFlexInaTTB); + #endif // TILE_LAYOUT + #if MONOCLE_LAYOUT + if (m->lt[m->sellt]->arrange == &monocle) + return (activegroup ? SchemeFlexActMONO : SchemeFlexInaMONO); + #endif // MONOCLE_LAYOUT + return SchemeTitleNorm; + case GRP_HIDDEN: + return SchemeHid; + case GRP_FLOAT: + return (activegroup ? SchemeFlexActFloat : SchemeFlexInaFloat); + } + return SchemeTitleNorm; +} + +int +getselschemefor(int scheme) +{ + if (scheme == SchemeFlexActFloat || scheme == SchemeFlexInaFloat) + return SchemeFlexSelFloat; + if (scheme >= SchemeFlexInaTTB) + return scheme + SchemeFlexInaTTB - SchemeFlexActTTB; + if (scheme >= SchemeFlexActTTB) + return scheme + SchemeFlexSelTTB - SchemeFlexActTTB; + return SchemeTitleSel; +} + +void +flextitledraw(Monitor *m, Client *c, int unused, int x, int w, int tabscheme, Arg *arg, BarArg *barg) +{ + if (!c) + return; + int i, nclienttags = 0, nviewtags = 0, pad = lrpad / 2; + int clientscheme = ( + c == selmon->sel + ? getselschemefor(tabscheme) + : HIDDEN(c) + ? SchemeHid + : c->isurgent + ? SchemeUrg + : tabscheme + ); + drw_setscheme(drw, scheme[clientscheme]); + XSetWindowBorder(dpy, c->win, scheme[clientscheme][ColBorder].pixel); + if (w <= TEXTW("A") - lrpad + pad) // reduce text padding if wintitle is too small + pad = (w - TEXTW("A") + lrpad < 0 ? 0 : (w - TEXTW("A") + lrpad) / 2); + #if BAR_CENTEREDWINDOWNAME_PATCH + else if (TEXTW(c->name) < w) + pad = (w - TEXTW(c->name) + lrpad) / 2; + #endif // BAR_CENTEREDWINDOWNAME_PATCH + + drw_text(drw, x, barg->y, w, barg->h, pad, c->name, 0, False); + drawstateindicator(m, c, 1, x + 2, barg->y, w, barg->h, 0, 0, 0); + + if (FLEXWINTITLE_BORDERS) { + XSetForeground(drw->dpy, drw->gc, scheme[SchemeSel][ColBorder].pixel); + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, barg->y, 1, barg->h); + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x + w - (x + w >= barg->w ? 1 : 0), barg->y, 1, barg->h); + } + /* Optional tags icons */ + for (i = 0; i < NUMTAGS; i++) { + if ((m->tagset[m->seltags] >> i) & 1) + nviewtags++; + if ((c->tags >> i) & 1) + nclienttags++; + } + + if (TAGSINDICATOR == 2 || nclienttags > 1 || nviewtags > 1) + drawindicator(m, c, 1, x, barg->y, w, barg->h, 0, 0, 0, INDICATOR_RIGHT_TAGS); +} + +#ifndef HIDDEN +#define HIDDEN(C) 0 +#endif + +void +flextitleclick(Monitor *m, Client *c, int passx, int x, int w, int unused, Arg *arg, BarArg *barg) +{ + if (passx >= x && passx <= x + w) + arg->v = c; +} + +int +flextitlecalculate( + Monitor *m, int offx, int tabw, int passx, + void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg), + Arg *arg, BarArg *barg +) { + Client *c; + int n, center = 0, mirror = 0, fixed = 0; // layout configuration + int clientsnmaster = 0, clientsnstack = 0, clientsnfloating = 0, clientsnhidden = 0; + int i, w, r, num = 0, den, fulllayout = 0; + int clientsnstack2 = 0; + int groupactive = 0; + int selidx = 0; + int dualstack = 0; + int rw, rr; + + int mas_x = offx, st1_x = offx, st2_x = offx, hid_x = offx, flt_x = offx; + int mas_w, st1_w, st2_w, hid_w; + + for (i = 0, c = m->clients; c; c = c->next) { + if (!ISVISIBLE(c)) + continue; + if (HIDDEN(c)) { + if (FLEXWINTITLE_HIDDENWEIGHT) + clientsnhidden++; + continue; + } + + if (c->isfloating) { + if (FLEXWINTITLE_FLOATWEIGHT) + clientsnfloating++; + continue; + } + + if (m->sel == c) + selidx = i; + + if (i < m->nmaster) + clientsnmaster++; + #if FLEXTILE_DELUXE_LAYOUT + else if (m->nstack) { + if (clientsnstack < m->nstack) + clientsnstack++; + else + clientsnstack2++; + } + #endif // FLEXTILE_DELUXE_LAYOUT + else if ((i - m->nmaster) % 2) + clientsnstack2++; + else + clientsnstack++; + i++; + } + + if (!m->sel) + groupactive = GRP_NOSELECTION; + else if (HIDDEN(m->sel)) + groupactive = GRP_HIDDEN; + else if (m->sel->isfloating) + groupactive = GRP_FLOAT; + else if (selidx < clientsnmaster) + groupactive = GRP_MASTER; + else if (selidx < clientsnmaster + clientsnstack) + groupactive = GRP_STACK1; + else if (selidx < clientsnmaster + clientsnstack + clientsnstack2) + groupactive = GRP_STACK2; + + n = clientsnmaster + clientsnstack + clientsnstack2 + clientsnfloating + clientsnhidden; + if (n == 0) + return 0; + #if FLEXTILE_DELUXE_LAYOUT + else if (m->lt[m->sellt]->arrange == &flextile) { + int layout = m->ltaxis[LAYOUT]; + if (layout < 0) { + mirror = 1; + layout *= -1; + } + if (layout > FLOATING_MASTER) { + layout -= FLOATING_MASTER; + fixed = 1; + } + + if (layout == SPLIT_HORIZONTAL_DUAL_STACK || layout == SPLIT_HORIZONTAL_DUAL_STACK_FIXED) + dualstack = 1; + else if (layout == SPLIT_CENTERED_VERTICAL && (fixed || n - m->nmaster > 1)) + center = 1; + else if (layout == FLOATING_MASTER) + center = 1; + else if (layout == SPLIT_CENTERED_HORIZONTAL) { + if (fixed || n - m->nmaster > 1) + center = 1; + } + } + #endif // FLEXTILE_DELUXE_LAYOUT + #if CENTEREDMASTER_LAYOUT + else if (m->lt[m->sellt]->arrange == ¢eredmaster && (fixed || n - m->nmaster > 1)) + center = 1; + #endif // CENTEREDMASTER_LAYOUT + #if CENTEREDFLOATINGMASTER_LAYOUT + else if (m->lt[m->sellt]->arrange == ¢eredfloatingmaster) + center = 1; + #endif // CENTEREDFLOATINGMASTER_LAYOUT + + /* Certain layouts have no master / stack areas */ + if (!m->lt[m->sellt]->arrange // floating layout + || (!n || (!fixed && m->nmaster && n <= m->nmaster)) // no master + #if MONOCLE_LAYOUT + || m->lt[m->sellt]->arrange == &monocle + #endif // MONOCLE_LAYOUT + #if GRIDMODE_LAYOUT + || m->lt[m->sellt]->arrange == &grid + #endif // GRIDMODE_LAYOUT + #if HORIZGRID_LAYOUT + || m->lt[m->sellt]->arrange == &horizgrid + #endif // HORIZGRID_LAYOUT + #if GAPPLESSGRID_LAYOUT + || m->lt[m->sellt]->arrange == &gaplessgrid + #endif // GAPPLESSGRID_LAYOUT + #if NROWGRID_LAYOUT + || m->lt[m->sellt]->arrange == &nrowgrid + #endif // NROWGRID_LAYOUT + #if FLEXTILE_DELUXE_LAYOUT + || (m->lt[m->sellt]->arrange == &flextile && m->ltaxis[LAYOUT] == NO_SPLIT) + #endif // FLEXTILE_DELUXE_LAYOUT + ) + fulllayout = 1; + + num = tabw; + c = m->clients; + + /* floating mode */ + if ((fulllayout && FLEXWINTITLE_FLOATWEIGHT > 0) || clientsnmaster + clientsnstack == 0 || !m->lt[m->sellt]->arrange) { + den = clientsnmaster + clientsnstack + clientsnstack2 + clientsnfloating + clientsnhidden; + w = num / den; + r = num % den; // rest + c = flextitledrawarea(m, c, mas_x, r, w, den, !m->lt[m->sellt]->arrange ? SchemeFlexActFloat : SCHEMEFOR(GRP_MASTER), 1, FLEXWINTITLE_HIDDENWEIGHT, FLEXWINTITLE_FLOATWEIGHT, passx, tabfn, arg, barg); // floating + /* no master and stack mode, e.g. monocole, grid layouts, fibonacci */ + } else if (fulllayout) { + den = clientsnmaster + clientsnstack + clientsnstack2 + clientsnhidden; + w = num / den; + r = num % den; // rest + c = flextitledrawarea(m, c, mas_x, r, w, den, SCHEMEFOR(GRP_MASTER), 1, FLEXWINTITLE_HIDDENWEIGHT, 0, passx, tabfn, arg, barg); // full + /* tiled mode */ + } else { + den = clientsnmaster * FLEXWINTITLE_MASTERWEIGHT + (clientsnstack + clientsnstack2) * FLEXWINTITLE_STACKWEIGHT + clientsnfloating * FLEXWINTITLE_FLOATWEIGHT + clientsnhidden * FLEXWINTITLE_HIDDENWEIGHT; + w = num / den; // weight width per client + r = num % den; // weight rest width + rw = r / n; // rest incr per client + rr = r % n; // rest rest + #if FLEXTILE_DELUXE_LAYOUT + if ((!center && !dualstack) || (center && n <= m->nmaster + (m->nstack ? m->nstack : 1))) + #else + if ((!center && !dualstack) || (center && n <= m->nmaster + 1)) + #endif // FLEXTILE_DELUXE_LAYOUT + { + clientsnstack += clientsnstack2; + clientsnstack2 = 0; + if (groupactive == GRP_STACK2) + groupactive = GRP_STACK1; + } + + mas_w = clientsnmaster * rw + w * clientsnmaster * FLEXWINTITLE_MASTERWEIGHT + (rr > 0 ? MIN(rr, clientsnmaster) : 0); + rr -= clientsnmaster; + st1_w = clientsnstack * (rw + w * FLEXWINTITLE_STACKWEIGHT) + (rr > 0 ? MIN(rr, clientsnstack) : 0); + rr -= clientsnstack; + st2_w = clientsnstack2 * (rw + w * FLEXWINTITLE_STACKWEIGHT) + (rr > 0 ? MIN(rr, clientsnstack2) : 0); + rr -= clientsnstack2; + hid_w = clientsnhidden * (rw + w * FLEXWINTITLE_HIDDENWEIGHT) + (rr > 0 ? MIN(rr, clientsnhidden) : 0); + rr -= clientsnhidden; + rr = r % n; + + if (mirror) { + if (center && clientsnstack2) { + mas_x = st1_x + st1_w; + st2_x = mas_x + mas_w; + hid_x = st2_x + st2_w; + } else { + if (clientsnstack2) { + st2_x = st1_x + st1_w; + mas_x = st2_x + st2_w; + } else + mas_x = st1_x + st1_w; + hid_x = mas_x + mas_w; + } + } else { + if (center && clientsnstack2) { + mas_x = st2_x + st2_w; + st1_x = mas_x + mas_w; + hid_x = st1_x + st1_w; + } else { + st1_x = mas_x + mas_w; + if (clientsnstack2) { + st2_x = st1_x + st1_w; + hid_x = st2_x + st2_w; + } else + hid_x = st1_x + st1_w; + } + } + + flt_x = hid_x + hid_w; + c = flextitledrawarea(m, c, mas_x, rr, w * FLEXWINTITLE_MASTERWEIGHT + rw, clientsnmaster, SCHEMEFOR(GRP_MASTER), 1, 0, 0, passx, tabfn, arg, barg); // master + rr -= clientsnmaster; + c = flextitledrawarea(m, c, st1_x, rr, w * FLEXWINTITLE_STACKWEIGHT + rw, clientsnstack, SCHEMEFOR(GRP_STACK1), 1, 0, 0, passx, tabfn, arg, barg); // stack1 + rr -= clientsnstack; + if (clientsnstack2) { + c = flextitledrawarea(m, c, st2_x, rr, w * FLEXWINTITLE_STACKWEIGHT + rw, clientsnstack2, SCHEMEFOR(GRP_STACK2), 1, 0, 0, passx, tabfn, arg, barg); // stack2 + rr -= clientsnstack2; + } + c = flextitledrawarea(m, m->clients, hid_x, rr, w * FLEXWINTITLE_HIDDENWEIGHT + rw, clientsnhidden, SCHEMEFOR(GRP_HIDDEN), 0, 1, 0, passx, tabfn, arg, barg); // hidden + rr -= clientsnhidden; + c = flextitledrawarea(m, m->clients, flt_x, rr, w * FLEXWINTITLE_FLOATWEIGHT + rw, clientsnfloating, SCHEMEFOR(GRP_FLOAT), 0, 0, 1, passx, tabfn, arg, barg); // floating + } + return 1; +} \ No newline at end of file diff --git a/suckless/dwm/patch/bar_flexwintitle.h b/suckless/dwm/patch/bar_flexwintitle.h new file mode 100644 index 00000000..6183c8e6 --- /dev/null +++ b/suckless/dwm/patch/bar_flexwintitle.h @@ -0,0 +1,10 @@ +static int width_flexwintitle(Bar *bar, BarArg *a); +static int draw_flexwintitle(Bar *bar, BarArg *a); +static int click_flexwintitle(Bar *bar, Arg *arg, BarArg *a); + +static void flextitledraw(Monitor *m, Client *c, int unused, int x, int w, int groupactive, Arg *arg, BarArg *barg); +static void flextitleclick(Monitor *m, Client *c, int passx, int x, int w, int unused, Arg *arg, BarArg *barg); +static int flextitlecalculate(Monitor *m, int offx, int w, int passx, void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg), Arg *arg, BarArg *barg); +static int getschemefor(Monitor *m, int group, int activegroup); +static int getselschemefor(int scheme); +static Client *flextitledrawarea(Monitor *m, Client *c, int x, int r, int w, int max_clients, int tabscheme, int draw_tiled, int draw_hidden, int draw_floating, int passx, void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg), Arg *arg, BarArg *barg); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_holdbar.c b/suckless/dwm/patch/bar_holdbar.c new file mode 100644 index 00000000..358cbec3 --- /dev/null +++ b/suckless/dwm/patch/bar_holdbar.c @@ -0,0 +1,37 @@ +void +holdbar(const Arg *arg) +{ + if (selmon->showbar) + return; + Bar *bar; + selmon->showbar = 2; + updatebarpos(selmon); + for (bar = selmon->bar; bar; bar = bar->next) + XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh); +} + +void +keyrelease(XEvent *e) +{ + Bar *bar; + if (XEventsQueued(dpy, QueuedAfterReading)) { + XEvent ne; + XPeekEvent(dpy, &ne); + + if (ne.type == KeyPress && ne.xkey.time == e->xkey.time && + ne.xkey.keycode == e->xkey.keycode) { + XNextEvent(dpy, &ne); + return; + } + } + if (e->xkey.keycode == XKeysymToKeycode(dpy, HOLDKEY) && selmon->showbar == 2) { + selmon->showbar = 0; + updatebarpos(selmon); + for (bar = selmon->bar; bar; bar = bar->next) + XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh); + arrange(selmon); + } + #if COMBO_PATCH + combo = 0; + #endif // COMBO_PATCH +} \ No newline at end of file diff --git a/suckless/dwm/patch/bar_holdbar.h b/suckless/dwm/patch/bar_holdbar.h new file mode 100644 index 00000000..53944251 --- /dev/null +++ b/suckless/dwm/patch/bar_holdbar.h @@ -0,0 +1,2 @@ +static void keyrelease(XEvent *e); +static void holdbar(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_indicators.c b/suckless/dwm/patch/bar_indicators.c new file mode 100644 index 00000000..644e0726 --- /dev/null +++ b/suckless/dwm/patch/bar_indicators.c @@ -0,0 +1,110 @@ +/* Indicator properties, you can override these in your config.h if you want. */ +#ifndef TAGSINDICATOR +#define TAGSINDICATOR 1 // 0 = off, 1 = on if >1 client/view tag, 2 = always on +#endif +#ifndef TAGSPX +#define TAGSPX 5 // # pixels for tag grid boxes +#endif +#ifndef TAGSROWS +#define TAGSROWS 3 // # rows in tag grid (9 tags, e.g. 3x3) +#endif + +void +drawindicator(Monitor *m, Client *c, unsigned int occ, int x, int y, int w, int h, unsigned int tag, int filled, int invert, int type) +{ + int i, boxw, boxs, indn = 0; + if (!(occ & 1 << tag) || type == INDICATOR_NONE) + return; + + boxs = drw->fonts->h / 9; + boxw = drw->fonts->h / 6 + 2; + if (filled == -1) + filled = m == selmon && m->sel && m->sel->tags & 1 << tag; + + switch (type) { + default: + case INDICATOR_TOP_LEFT_SQUARE: + drw_rect(drw, x + boxs, y + boxs, boxw, boxw, filled, invert); + break; + case INDICATOR_TOP_LEFT_LARGER_SQUARE: + drw_rect(drw, x + boxs + 2, y + boxs+1, boxw+1, boxw+1, filled, invert); + break; + case INDICATOR_TOP_BAR: + drw_rect(drw, x + boxw, y, w - ( 2 * boxw + 1), boxw/2, filled, invert); + break; + case INDICATOR_TOP_BAR_SLIM: + drw_rect(drw, x + boxw, y, w - ( 2 * boxw + 1), 1, 0, invert); + break; + case INDICATOR_BOTTOM_BAR: + drw_rect(drw, x + boxw, y + h - boxw/2, w - ( 2 * boxw + 1), boxw/2, filled, invert); + break; + case INDICATOR_BOTTOM_BAR_SLIM: + drw_rect(drw, x + boxw, y + h - 1, w - ( 2 * boxw + 1), 1, 0, invert); + break; + case INDICATOR_BOX: + drw_rect(drw, x + boxw, y, w - 2 * boxw, h, 0, invert); + break; + case INDICATOR_BOX_WIDER: + drw_rect(drw, x + boxw/2, y, w - boxw, h, 0, invert); + break; + case INDICATOR_BOX_FULL: + drw_rect(drw, x, y, w - 2, h, 0, invert); + break; + case INDICATOR_CLIENT_DOTS: + for (c = m->clients; c; c = c->next) { + if (c->tags & (1 << tag)) { + drw_rect(drw, x, 1 + (indn * 2), m->sel == c ? 6 : 1, 1, 1, invert); + indn++; + } + if (h <= 1 + (indn * 2)) { + indn = 0; + x += 2; + } + } + break; + case INDICATOR_RIGHT_TAGS: + if (!c) + break; + for (i = 0; i < NUMTAGS; i++) { + drw_rect(drw, + ( x + w - 2 - ((NUMTAGS / TAGSROWS) * TAGSPX) + - (i % (NUMTAGS/TAGSROWS)) + ((i % (NUMTAGS / TAGSROWS)) * TAGSPX) + ), + ( y + 2 + ((i / (NUMTAGS/TAGSROWS)) * TAGSPX) + - ((i / (NUMTAGS/TAGSROWS))) + ), + TAGSPX, TAGSPX, (c->tags >> i) & 1, 0 + ); + } + break; + case INDICATOR_PLUS_AND_LARGER_SQUARE: + boxs += 2; + boxw += 2; + /* falls through */ + case INDICATOR_PLUS_AND_SQUARE: + drw_rect(drw, x + boxs, y + boxs, boxw % 2 ? boxw : boxw + 1, boxw % 2 ? boxw : boxw + 1, filled, invert); + /* falls through */ + case INDICATOR_PLUS: + if (!(boxw % 2)) + boxw += 1; + drw_rect(drw, x + boxs + boxw / 2, y + boxs, 1, boxw, filled, invert); // | + drw_rect(drw, x + boxs, y + boxs + boxw / 2, boxw + 1, 1, filled, invert); // ‒ + break; + } +} + +void +drawstateindicator(Monitor *m, Client *c, unsigned int occ, int x, int y, int w, int h, unsigned int tag, int filled, int invert) +{ + #if FAKEFULLSCREEN_CLIENT_PATCH + if (c->fakefullscreen && c->isfloating) + drawindicator(m, c, occ, x, y, w, h, tag, filled, invert, floatfakefsindicatortype); + else if (c->fakefullscreen) + drawindicator(m, c, occ, x, y, w, h, tag, filled, invert, fakefsindicatortype); + else + #endif // FAKEFULLSCREEN_CLIENT_PATCH + if (c->isfloating) + drawindicator(m, c, occ, x, y, w, h, tag, filled, invert, floatindicatortype); + else + drawindicator(m, c, occ, x, y, w, h, tag, filled, invert, tiledindicatortype); +} \ No newline at end of file diff --git a/suckless/dwm/patch/bar_indicators.h b/suckless/dwm/patch/bar_indicators.h new file mode 100644 index 00000000..d015101a --- /dev/null +++ b/suckless/dwm/patch/bar_indicators.h @@ -0,0 +1,20 @@ +enum { + INDICATOR_NONE, + INDICATOR_TOP_LEFT_SQUARE, + INDICATOR_TOP_LEFT_LARGER_SQUARE, + INDICATOR_TOP_BAR, + INDICATOR_TOP_BAR_SLIM, + INDICATOR_BOTTOM_BAR, + INDICATOR_BOTTOM_BAR_SLIM, + INDICATOR_BOX, + INDICATOR_BOX_WIDER, + INDICATOR_BOX_FULL, + INDICATOR_CLIENT_DOTS, + INDICATOR_RIGHT_TAGS, + INDICATOR_PLUS, + INDICATOR_PLUS_AND_SQUARE, + INDICATOR_PLUS_AND_LARGER_SQUARE, +}; + +static void drawindicator(Monitor *m, Client *c, unsigned int occ, int x, int y, int w, int h, unsigned int tag, int filled, int invert, int type); +static void drawstateindicator(Monitor *m, Client *c, unsigned int occ, int x, int y, int w, int h, unsigned int tag, int filled, int invert); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_layoutmenu.c b/suckless/dwm/patch/bar_layoutmenu.c new file mode 100644 index 00000000..1b950695 --- /dev/null +++ b/suckless/dwm/patch/bar_layoutmenu.c @@ -0,0 +1,18 @@ +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') + return; + + i = atoi(c); + setlayout(&((Arg) { .v = &layouts[i] })); +} + diff --git a/suckless/dwm/patch/bar_layoutmenu.h b/suckless/dwm/patch/bar_layoutmenu.h new file mode 100644 index 00000000..4c237630 --- /dev/null +++ b/suckless/dwm/patch/bar_layoutmenu.h @@ -0,0 +1 @@ +static void layoutmenu(const Arg *arg); diff --git a/suckless/dwm/patch/bar_ltsymbol.c b/suckless/dwm/patch/bar_ltsymbol.c new file mode 100644 index 00000000..4c861f87 --- /dev/null +++ b/suckless/dwm/patch/bar_ltsymbol.c @@ -0,0 +1,17 @@ +int +width_ltsymbol(Bar *bar, BarArg *a) +{ + return TEXTW(bar->mon->ltsymbol); +} + +int +draw_ltsymbol(Bar *bar, BarArg *a) +{ + return drw_text(drw, a->x, a->y, a->w, a->h, lrpad / 2, bar->mon->ltsymbol, 0, False); +} + +int +click_ltsymbol(Bar *bar, Arg *arg, BarArg *a) +{ + return ClkLtSymbol; +} \ No newline at end of file diff --git a/suckless/dwm/patch/bar_ltsymbol.h b/suckless/dwm/patch/bar_ltsymbol.h new file mode 100644 index 00000000..41885841 --- /dev/null +++ b/suckless/dwm/patch/bar_ltsymbol.h @@ -0,0 +1,3 @@ +static int width_ltsymbol(Bar *bar, BarArg *a); +static int draw_ltsymbol(Bar *bar, BarArg *a); +static int click_ltsymbol(Bar *bar, Arg *arg, BarArg *a); diff --git a/suckless/dwm/patch/bar_powerline_status.c b/suckless/dwm/patch/bar_powerline_status.c new file mode 100644 index 00000000..2f95570a --- /dev/null +++ b/suckless/dwm/patch/bar_powerline_status.c @@ -0,0 +1,121 @@ +static Clr **statusscheme; + +int +width_pwrl_status(Bar *bar, BarArg *a) +{ + #if BAR_STATUSCMD_PATCH + return widthpowerlinestatus(rawstext); + #else + return widthpowerlinestatus(stext); + #endif // BAR_STATUSCMD_PATCH +} + +#if BAR_EXTRASTATUS_PATCH +int +width_pwrl_status_es(Bar *bar, BarArg *a) +{ + #if BAR_STATUSCMD_PATCH + return widthpowerlinestatus(rawestext); + #else + return widthpowerlinestatus(estext); + #endif // BAR_STATUSCMD_PATCH +} +#endif // BAR_EXTRASTATUS_PATCH + +int +draw_pwrl_status(Bar *bar, BarArg *a) +{ + #if BAR_STATUSCMD_PATCH + return drawpowerlinestatus(a->x + a->w, rawstext, a); + #else + return drawpowerlinestatus(a->x + a->w, stext, a); + #endif // BAR_STATUSCMD_PATCH +} + +#if BAR_EXTRASTATUS_PATCH +int +draw_pwrl_status_es(Bar *bar, BarArg *a) +{ + #if BAR_STATUSCMD_PATCH + return drawpowerlinestatus(a->x + a->w, rawestext, a); + #else + return drawpowerlinestatus(a->x + a->w, estext, a); + #endif // BAR_STATUSCMD_PATCH +} +#endif // BAR_EXTRASTATUS_PATCH + +int +click_pwrl_status(Bar *bar, Arg *arg, BarArg *a) +{ + return ClkStatusText; +} + +int +widthpowerlinestatus(char *stext) +{ + char status[512]; + int w = 0, i, n = strlen(stext); + int plw = drw->fonts->h / 2 + 1; + char *bs, bp = '|'; + strcpy(status, stext); + + for (i = n, bs = &status[n-1]; i >= 0; i--, bs--) { + if (*bs == '<' || *bs == '/' || *bs == '\\' || *bs == '>' || *bs == '|') { /* block start */ + if (bp != '|') + w += plw; + w += TEXTW(bs+2); + bp = *bs; + *bs = 0; + } + } + if (bp != '|') + w += plw * 2; + + return w; +} + +int +drawpowerlinestatus(int xpos, char *stext, BarArg *barg) +{ + char status[512]; + int i, n = strlen(stext), cn = 0; + int x = xpos, w = 0; + int plw = drw->fonts->h / 2 + 1; + char *bs, bp = '|'; + Clr *prevscheme = statusscheme[0], *nxtscheme; + strcpy(status, stext); + + for (i = n, bs = &status[n-1]; i >= 0; i--, bs--) { + if (*bs == '<' || *bs == '/' || *bs == '\\' || *bs == '>' || *bs == '|') { /* block start */ + cn = ((int) *(bs+1)) - 1; + + if (cn < LENGTH(statuscolors)) { + drw_settrans(drw, prevscheme, (nxtscheme = statusscheme[cn])); + } else { + drw_settrans(drw, prevscheme, (nxtscheme = statusscheme[0])); + } + + if (bp != '|') { + drw_arrow(drw, x - plw, barg->y, plw, barg->h, bp == '\\' || bp == '>' ? 1 : 0, bp == '<' ? 0 : 1); + x -= plw; + } + + drw_setscheme(drw, nxtscheme); + w = TEXTW(bs+2); + drw_text(drw, x - w, barg->y, w, barg->h, lrpad / 2, bs+2, 0, False); + x -= w; + + bp = *bs; + *bs = 0; + prevscheme = nxtscheme; + } + } + if (bp != '|') { + drw_settrans(drw, prevscheme, scheme[SchemeNorm]); + drw_arrow(drw, x - plw, barg->y, plw, barg->h, bp == '\\' || bp == '>' ? 1 : 0, bp == '<' ? 0 : 1); + drw_rect(drw, x - 2 * plw, barg->y, plw, barg->h, 1, 1); + x -= plw * 2; + } + + return xpos - x; +} \ No newline at end of file diff --git a/suckless/dwm/patch/bar_powerline_status.h b/suckless/dwm/patch/bar_powerline_status.h new file mode 100644 index 00000000..1eb68240 --- /dev/null +++ b/suckless/dwm/patch/bar_powerline_status.h @@ -0,0 +1,11 @@ +static int width_pwrl_status(Bar *bar, BarArg *a); +#if BAR_EXTRASTATUS_PATCH +static int width_pwrl_status_es(Bar *bar, BarArg *a); +#endif // BAR_EXTRASTATUS_PATCH +static int draw_pwrl_status(Bar *bar, BarArg *a); +#if BAR_EXTRASTATUS_PATCH +static int draw_pwrl_status_es(Bar *bar, BarArg *a); +#endif // BAR_EXTRASTATUS_PATCH +static int click_pwrl_status(Bar *bar, Arg *arg, BarArg *a); +static int drawpowerlinestatus(int x, char *stext, BarArg *a); +static int widthpowerlinestatus(char *stext); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_powerline_tags.c b/suckless/dwm/patch/bar_powerline_tags.c new file mode 100644 index 00000000..f4dd9237 --- /dev/null +++ b/suckless/dwm/patch/bar_powerline_tags.c @@ -0,0 +1,106 @@ +int +width_pwrl_tags(Bar *bar, BarArg *a) +{ + int w, i; + int plw = drw->fonts->h / 2 + 1; + #if BAR_HIDEVACANTTAGS_PATCH + Client *c; + unsigned int occ = 0; + for (c = bar->mon->clients; c; c = c->next) + occ |= c->tags == 255 ? 0 : c->tags; + #endif // BAR_HIDEVACANTTAGS_PATCH + + for (w = 0, i = 0; i < NUMTAGS; i++) { + #if BAR_HIDEVACANTTAGS_PATCH + if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i)) + continue; + #endif // BAR_HIDEVACANTTAGS_PATCH + w += TEXTW(tagicon(bar->mon, i)) + plw; + } + return w + lrpad; +} + +int +draw_pwrl_tags(Bar *bar, BarArg *a) +{ + int x, w; + int invert; + int plw = drw->fonts->h / 2 + 1; + unsigned int i, occ = 0, urg = 0; + char *icon; + Client *c; + Clr *prevscheme, *nxtscheme; + + for (c = bar->mon->clients; c; c = c->next) { + #if BAR_HIDEVACANTTAGS_PATCH + occ |= c->tags == 255 ? 0 : c->tags; + #else + occ |= c->tags; + #endif // BAR_HIDEVACANTTAGS_PATCH + if (c->isurgent) + urg |= c->tags; + } + x = a->x; + prevscheme = scheme[SchemeNorm]; + for (i = 0; i < NUMTAGS; i++) { + #if BAR_HIDEVACANTTAGS_PATCH + /* do not draw vacant tags */ + if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i)) + continue; + #endif // BAR_HIDEVACANTTAGS_PATCH + + icon = tagicon(bar->mon, i); + invert = 0; + w = TEXTW(icon); + if (urg & 1 << i ) { + drw_settrans(drw, prevscheme, (nxtscheme = scheme[bar->mon->tagset[bar->mon->seltags] & 1 << i ? SchemeSel : SchemeUrg])); + } else { + drw_settrans(drw, prevscheme, (nxtscheme = scheme[bar->mon->tagset[bar->mon->seltags] & 1 << i ? SchemeSel : SchemeNorm])); + } + #if BAR_POWERLINE_TAGS_SLASH_PATCH + drw_arrow(drw, x, a->y, plw, a->h, 1, 1); + #else + drw_arrow(drw, x, a->y, plw, a->h, 1, 0); + #endif // BAR_POWERLINE_TAGS_SLASH_PATCH + x += plw; + drw_setscheme(drw, nxtscheme); + drw_text(drw, x, a->y, w, a->h, lrpad / 2, icon, invert, False); + drawindicator(bar->mon, NULL, occ, x, a->y, w, a->h, i, -1, invert, tagindicatortype); + x += w; + prevscheme = nxtscheme; + } + nxtscheme = scheme[SchemeNorm]; + + drw_settrans(drw, prevscheme, nxtscheme); + #if BAR_POWERLINE_TAGS_SLASH_PATCH + drw_arrow(drw, x, a->y, plw, a->h, 1, 1); + #else + drw_arrow(drw, x, a->y, plw, a->h, 1, 0); + #endif // BAR_POWERLINE_TAGS_SLASH_PATCH + return 1; +} + +int +click_pwrl_tags(Bar *bar, Arg *arg, BarArg *a) +{ + int i = 0, x = lrpad / 2; + int plw = drw->fonts->h / 2 + 1; + #if BAR_HIDEVACANTTAGS_PATCH + Client *c; + unsigned int occ = 0; + for (c = bar->mon->clients; c; c = c->next) + occ |= c->tags == 255 ? 0 : c->tags; + #endif // BAR_HIDEVACANTTAGS_PATCH + + do { + #if BAR_HIDEVACANTTAGS_PATCH + if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i)) + continue; + #endif // BAR_HIDEVACANTTAGS_PATCH + x += TEXTW(tagicon(bar->mon, i)) + plw; + } while (a->x >= x && ++i < NUMTAGS); + if (i < NUMTAGS) { + arg->ui = 1 << i; + } + return ClkTagBar; +} diff --git a/suckless/dwm/patch/bar_powerline_tags.h b/suckless/dwm/patch/bar_powerline_tags.h new file mode 100644 index 00000000..f942ff10 --- /dev/null +++ b/suckless/dwm/patch/bar_powerline_tags.h @@ -0,0 +1,3 @@ +static int width_pwrl_tags(Bar *bar, BarArg *a); +static int draw_pwrl_tags(Bar *bar, BarArg *a); +static int click_pwrl_tags(Bar *bar, Arg *arg, BarArg *a); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_status.c b/suckless/dwm/patch/bar_status.c new file mode 100644 index 00000000..d37424df --- /dev/null +++ b/suckless/dwm/patch/bar_status.c @@ -0,0 +1,33 @@ +int +width_status(Bar *bar, BarArg *a) +{ + return TEXTWM(stext); +} + +#if BAR_EXTRASTATUS_PATCH +int +width_status_es(Bar *bar, BarArg *a) +{ + return TEXTWM(estext) - lrpad; +} +#endif // BAR_EXTRASTATUS_PATCH + +int +draw_status(Bar *bar, BarArg *a) +{ + return drw_text(drw, a->x, a->y, a->w, a->h, lrpad / 2, stext, 0, True); +} + +#if BAR_EXTRASTATUS_PATCH +int +draw_status_es(Bar *bar, BarArg *a) +{ + return drw_text(drw, a->x, a->y, a->w, a->h, 0, estext, 0, True); +} +#endif // BAR_EXTRASTATUS_PATCH + +int +click_status(Bar *bar, Arg *arg, BarArg *a) +{ + return ClkStatusText; +} diff --git a/suckless/dwm/patch/bar_status.h b/suckless/dwm/patch/bar_status.h new file mode 100644 index 00000000..e6d8ab01 --- /dev/null +++ b/suckless/dwm/patch/bar_status.h @@ -0,0 +1,9 @@ +static int width_status(Bar *bar, BarArg *a); +#if BAR_EXTRASTATUS_PATCH +static int width_status_es(Bar *bar, BarArg *a); +#endif // BAR_EXTRASTATUS_PATCH +static int draw_status(Bar *bar, BarArg *a); +#if BAR_EXTRASTATUS_PATCH +static int draw_status_es(Bar *bar, BarArg *a); +#endif // BAR_EXTRASTATUS_PATCH +static int click_status(Bar *bar, Arg *arg, BarArg *a); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_status2d.c b/suckless/dwm/patch/bar_status2d.c new file mode 100644 index 00000000..54e008d4 --- /dev/null +++ b/suckless/dwm/patch/bar_status2d.c @@ -0,0 +1,262 @@ +#if BAR_STATUS2D_XRDB_TERMCOLORS_PATCH +static char termcol0[] = "#000000"; /* black */ +static char termcol1[] = "#ff0000"; /* red */ +static char termcol2[] = "#33ff00"; /* green */ +static char termcol3[] = "#ff0099"; /* yellow */ +static char termcol4[] = "#0066ff"; /* blue */ +static char termcol5[] = "#cc00ff"; /* magenta */ +static char termcol6[] = "#00ffff"; /* cyan */ +static char termcol7[] = "#d0d0d0"; /* white */ +static char termcol8[] = "#808080"; /* black */ +static char termcol9[] = "#ff0000"; /* red */ +static char termcol10[] = "#33ff00"; /* green */ +static char termcol11[] = "#ff0099"; /* yellow */ +static char termcol12[] = "#0066ff"; /* blue */ +static char termcol13[] = "#cc00ff"; /* magenta */ +static char termcol14[] = "#00ffff"; /* cyan */ +static char termcol15[] = "#ffffff"; /* white */ +static char *termcolor[] = { + termcol0, termcol1, termcol2, termcol3, termcol4, termcol5, termcol6, termcol7, + termcol8, termcol9, termcol10, termcol11, termcol12, termcol13, termcol14, termcol15, +}; +#endif // BAR_STATUS2D_XRDB_TERMCOLORS_PATCH + +int +width_status2d(Bar *bar, BarArg *a) +{ + int width; + #if BAR_EXTRASTATUS_PATCH || BAR_STATUSCMD_PATCH + width = status2dtextlength(rawstext); + #else + width = status2dtextlength(stext); + #endif // #if BAR_EXTRASTATUS_PATCH | BAR_STATUSCMD_PATCH + return width ? width + lrpad : 0; +} + +#if BAR_EXTRASTATUS_PATCH +int +width_status2d_es(Bar *bar, BarArg *a) +{ + int width; + #if BAR_STATUSCMD_PATCH + width = status2dtextlength(rawestext); + #else + width = status2dtextlength(estext); + #endif // BAR_STATUSCMD_PATCH + return width ? width + lrpad : 0; +} +#endif // BAR_EXTRASTATUS_PATCH + +int +draw_status2d(Bar *bar, BarArg *a) +{ + #if BAR_EXTRASTATUS_PATCH || BAR_STATUSCMD_PATCH + return drawstatusbar(a, rawstext); + #else + return drawstatusbar(a, stext); + #endif // #if BAR_EXTRASTATUS_PATCH | BAR_STATUSCMD_PATCH +} + +#if BAR_EXTRASTATUS_PATCH +int +draw_status2d_es(Bar *bar, BarArg *a) +{ + #if BAR_STATUSCMD_PATCH + return drawstatusbar(a, rawestext); + #else + return drawstatusbar(a, estext); + #endif // BAR_STATUSCMD_PATCH +} +#endif // BAR_EXTRASTATUS_PATCH + +#if !BAR_STATUSCMD_PATCH +int +click_status2d(Bar *bar, Arg *arg, BarArg *a) +{ + return ClkStatusText; +} +#endif // BAR_STATUSCMD_PATCH + +int +drawstatusbar(BarArg *a, char* stext) +{ + int i, w, len; + int x = a->x; + int y = a->y; + short isCode = 0; + char *text; + char *p; + Clr oldbg, oldfg; + len = strlen(stext) + 1; + if (!(text = (char*) malloc(sizeof(char)*len))) + die("malloc"); + p = text; + #if BAR_STATUSCMD_PATCH + copyvalidchars(text, stext); + #else + memcpy(text, stext, len); + #endif // BAR_STATUSCMD_PATCH + + x += lrpad / 2; + drw_setscheme(drw, scheme[LENGTH(colors)]); + drw->scheme[ColFg] = scheme[SchemeNorm][ColFg]; + drw->scheme[ColBg] = scheme[SchemeNorm][ColBg]; + + /* process status text */ + i = -1; + while (text[++i]) { + if (text[i] == '^' && !isCode) { + isCode = 1; + + text[i] = '\0'; + w = TEXTWM(text) - lrpad; + drw_text(drw, x, y, w, bh, 0, text, 0, True); + + x += w; + + /* process code */ + while (text[++i] != '^') { + if (text[i] == 'c') { + char buf[8]; + if (i + 7 > len) { + i += 7; + break; + } + memcpy(buf, (char*)text+i+1, 7); + buf[7] = '\0'; + #if BAR_ALPHA_PATCH && BAR_STATUS2D_NO_ALPHA_PATCH + drw_clr_create(drw, &drw->scheme[ColFg], buf, 0xff); + #elif BAR_ALPHA_PATCH + drw_clr_create(drw, &drw->scheme[ColFg], buf, alphas[SchemeNorm][ColFg]); + #else + drw_clr_create(drw, &drw->scheme[ColFg], buf); + #endif // BAR_ALPHA_PATCH + i += 7; + } else if (text[i] == 'b') { + char buf[8]; + if (i + 7 > len) { + i += 7; + break; + } + memcpy(buf, (char*)text+i+1, 7); + buf[7] = '\0'; + #if BAR_ALPHA_PATCH && BAR_STATUS2D_NO_ALPHA_PATCH + drw_clr_create(drw, &drw->scheme[ColBg], buf, 0xff); + #elif BAR_ALPHA_PATCH + drw_clr_create(drw, &drw->scheme[ColBg], buf, alphas[SchemeNorm][ColBg]); + #else + drw_clr_create(drw, &drw->scheme[ColBg], buf); + #endif // BAR_ALPHA_PATCH + i += 7; + #if BAR_STATUS2D_XRDB_TERMCOLORS_PATCH + } else if (text[i] == 'C') { + int c = atoi(text + ++i) % 16; + #if BAR_ALPHA_PATCH && BAR_STATUS2D_NO_ALPHA_PATCH + drw_clr_create(drw, &drw->scheme[ColFg], termcolor[c], 0xff); + #elif BAR_ALPHA_PATCH + drw_clr_create(drw, &drw->scheme[ColFg], termcolor[c], alphas[SchemeNorm][ColBg]); + #else + drw_clr_create(drw, &drw->scheme[ColFg], termcolor[c]); + #endif // BAR_ALPHA_PATCH + } else if (text[i] == 'B') { + int c = atoi(text + ++i) % 16; + #if BAR_ALPHA_PATCH && BAR_STATUS2D_NO_ALPHA_PATCH + drw_clr_create(drw, &drw->scheme[ColBg], termcolor[c], 0xff); + #elif BAR_ALPHA_PATCH + drw_clr_create(drw, &drw->scheme[ColBg], termcolor[c], alphas[SchemeNorm][ColBg]); + #else + drw_clr_create(drw, &drw->scheme[ColBg], termcolor[c]); + #endif // BAR_ALPHA_PATCH + #endif // BAR_STATUS2D_XRDB_TERMCOLORS_PATCH + } else if (text[i] == 'd') { + drw->scheme[ColFg] = scheme[SchemeNorm][ColFg]; + drw->scheme[ColBg] = scheme[SchemeNorm][ColBg]; + } else if (text[i] == 'w') { + Clr swp; + swp = drw->scheme[ColFg]; + drw->scheme[ColFg] = drw->scheme[ColBg]; + drw->scheme[ColBg] = swp; + } else if (text[i] == 'v') { + oldfg = drw->scheme[ColFg]; + oldbg = drw->scheme[ColBg]; + } else if (text[i] == 't') { + drw->scheme[ColFg] = oldfg; + drw->scheme[ColBg] = oldbg; + } else if (text[i] == 'r') { + int rx = atoi(text + ++i); + while (text[++i] != ','); + int ry = atoi(text + ++i); + while (text[++i] != ','); + int rw = atoi(text + ++i); + while (text[++i] != ','); + int rh = atoi(text + ++i); + + if (ry < 0) + ry = 0; + if (rx < 0) + rx = 0; + + drw_rect(drw, rx + x, y + ry, rw, rh, 1, 0); + } else if (text[i] == 'f') { + x += atoi(text + ++i); + } + } + + text = text + i + 1; + i=-1; + isCode = 0; + } + } + if (!isCode) { + w = TEXTWM(text) - lrpad; + drw_text(drw, x, y, w, bh, 0, text, 0, True); + x += w; + } + free(p); + + drw_setscheme(drw, scheme[SchemeNorm]); + return len - 1; +} + +int +status2dtextlength(char* stext) +{ + int i, w, len; + short isCode = 0; + char *text; + char *p; + + len = strlen(stext) + 1; + if (!(text = (char*) malloc(sizeof(char)*len))) + die("malloc"); + p = text; + #if BAR_STATUSCMD_PATCH + copyvalidchars(text, stext); + #else + memcpy(text, stext, len); + #endif // BAR_STATUSCMD_PATCH + + /* compute width of the status text */ + w = 0; + i = -1; + while (text[++i]) { + if (text[i] == '^') { + if (!isCode) { + isCode = 1; + text[i] = '\0'; + w += TEXTWM(text) - lrpad; + text[i] = '^'; + if (text[++i] == 'f') + w += atoi(text + ++i); + } else { + isCode = 0; + text = text + i + 1; + i = -1; + } + } + } + if (!isCode) + w += TEXTWM(text) - lrpad; + free(p); + return w; +} \ No newline at end of file diff --git a/suckless/dwm/patch/bar_status2d.h b/suckless/dwm/patch/bar_status2d.h new file mode 100644 index 00000000..868a5681 --- /dev/null +++ b/suckless/dwm/patch/bar_status2d.h @@ -0,0 +1,13 @@ +static int width_status2d(Bar *bar, BarArg *a); +#if BAR_EXTRASTATUS_PATCH +static int width_status2d_es(Bar *bar, BarArg *a); +#endif // BAR_EXTRASTATUS_PATCH +static int draw_status2d(Bar *bar, BarArg *a); +#if BAR_EXTRASTATUS_PATCH +static int draw_status2d_es(Bar *bar, BarArg *a); +#endif // BAR_EXTRASTATUS_PATCH +#if !BAR_STATUSCMD_PATCH +static int click_status2d(Bar *bar, Arg *arg, BarArg *a); +#endif // BAR_STATUSCMD_PATCH +static int drawstatusbar(BarArg *a, char *text); +static int status2dtextlength(char *stext); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_statusbutton.c b/suckless/dwm/patch/bar_statusbutton.c new file mode 100644 index 00000000..7f52af41 --- /dev/null +++ b/suckless/dwm/patch/bar_statusbutton.c @@ -0,0 +1,17 @@ +int +width_stbutton(Bar *bar, BarArg *a) +{ + return TEXTW(buttonbar); +} + +int +draw_stbutton(Bar *bar, BarArg *a) +{ + return drw_text(drw, a->x, a->y, a->w, a->h, lrpad / 2, buttonbar, 0, False); +} + +int +click_stbutton(Bar *bar, Arg *arg, BarArg *a) +{ + return ClkButton; +} diff --git a/suckless/dwm/patch/bar_statusbutton.h b/suckless/dwm/patch/bar_statusbutton.h new file mode 100644 index 00000000..68ae839a --- /dev/null +++ b/suckless/dwm/patch/bar_statusbutton.h @@ -0,0 +1,3 @@ +static int width_stbutton(Bar *bar, BarArg *a); +static int draw_stbutton(Bar *bar, BarArg *a); +static int click_stbutton(Bar *bar, Arg *arg, BarArg *a); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_statuscmd.c b/suckless/dwm/patch/bar_statuscmd.c new file mode 100644 index 00000000..0a4ad722 --- /dev/null +++ b/suckless/dwm/patch/bar_statuscmd.c @@ -0,0 +1,74 @@ +#if !BAR_DWMBLOCKS_PATCH +static const char statusexport[] = "export BUTTON=-;"; +static int statuscmdn; +static int lastbutton; +#endif // BAR_DWMBLOCKS_PATCH + +int +click_statuscmd(Bar *bar, Arg *arg, BarArg *a) +{ + return click_statuscmd_text(arg, a->x, rawstext); +} + +#if BAR_EXTRASTATUS_PATCH +int +click_statuscmd_es(Bar *bar, Arg *arg, BarArg *a) +{ + return click_statuscmd_text(arg, a->x, rawestext); +} +#endif // BAR_EXTRASTATUS_PATCH + +int +click_statuscmd_text(Arg *arg, int rel_x, char *text) +{ + int i = -1; + int x = 0; + char ch; + #if BAR_DWMBLOCKS_PATCH + dwmblockssig = -1; + #else + statuscmdn = 0; + #endif // BAR_DWMBLOCKS_PATCH + while (text[++i]) { + if ((unsigned char)text[i] < ' ') { + ch = text[i]; + text[i] = '\0'; + #if BAR_STATUS2D_PATCH && !BAR_BAR_STATUSCOLORS_PATCH + x += status2dtextlength(text); + #else + x += TEXTWM(text) - lrpad; + #endif // BAR_STATUS2D_PATCH + text[i] = ch; + text += i+1; + i = -1; + #if BAR_DWMBLOCKS_PATCH + if (x >= rel_x && dwmblockssig != -1) + break; + dwmblockssig = ch; + #else + if (x >= rel_x) + break; + if (ch <= LENGTH(statuscmds)) + statuscmdn = ch - 1; + #endif // BAR_DWMBLOCKS_PATCH + } + } + #if BAR_DWMBLOCKS_PATCH + if (dwmblockssig == -1) + dwmblockssig = 0; + #endif // BAR_DWMBLOCKS_PATCH + return ClkStatusText; +} + +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'; +} diff --git a/suckless/dwm/patch/bar_statuscmd.h b/suckless/dwm/patch/bar_statuscmd.h new file mode 100644 index 00000000..e2e75b16 --- /dev/null +++ b/suckless/dwm/patch/bar_statuscmd.h @@ -0,0 +1,6 @@ +static int click_statuscmd(Bar *bar, Arg *arg, BarArg *a); +#if BAR_EXTRASTATUS_PATCH +static int click_statuscmd_es(Bar *bar, Arg *arg, BarArg *a); +#endif // BAR_EXTRASTATUS_PATCH +static int click_statuscmd_text(Arg *arg, int rel_x, char *text); +static void copyvalidchars(char *text, char *rawtext); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_statuscolors.c b/suckless/dwm/patch/bar_statuscolors.c new file mode 100644 index 00000000..a443056f --- /dev/null +++ b/suckless/dwm/patch/bar_statuscolors.c @@ -0,0 +1,23 @@ +int +textw_wosc(char *s) +{ + char *ts = s; + char *tp = s; + int sw = 0; + char ctmp; + while (1) { + if ((unsigned int)*ts > LENGTH(colors)) { + ts++; + continue; + } + ctmp = *ts; + *ts = '\0'; + sw += drw_fontset_getwidth(drw, tp, True); + *ts = ctmp; + if (ctmp == '\0') + break; + tp = ++ts; + } + + return sw; +} \ No newline at end of file diff --git a/suckless/dwm/patch/bar_systray.c b/suckless/dwm/patch/bar_systray.c new file mode 100644 index 00000000..b20b45e2 --- /dev/null +++ b/suckless/dwm/patch/bar_systray.c @@ -0,0 +1,197 @@ +static Systray *systray = NULL; +static unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ; + +int +width_systray(Bar *bar, BarArg *a) +{ + unsigned int w = 0; + Client *i; + if (!systray) + return 1; + if (showsystray) + for (i = systray->icons; i; w += i->w + systrayspacing, i = i->next); + return w ? w + lrpad - systrayspacing : 0; +} + +int +draw_systray(Bar *bar, BarArg *a) +{ + if (!showsystray) + return 0; + + XSetWindowAttributes wa; + XWindowChanges wc; + Client *i; + unsigned int w; + + if (!systray) { + /* init systray */ + if (!(systray = (Systray *)calloc(1, sizeof(Systray)))) + die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); + + wa.override_redirect = True; + wa.event_mask = ButtonPressMask|ExposureMask; + wa.border_pixel = 0; + systray->h = MIN(a->h, drw->fonts->h); + #if BAR_ALPHA_PATCH + wa.background_pixel = 0; + wa.colormap = cmap; + systray->win = XCreateWindow(dpy, root, bar->bx + a->x + lrpad / 2, bar->by + a->y + (a->h - systray->h) / 2, MAX(a->w + 40, 1), systray->h, 0, depth, + InputOutput, visual, + CWOverrideRedirect|CWBorderPixel|CWBackPixel|CWColormap|CWEventMask, &wa); // CWBackPixmap + #else + wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; + systray->win = XCreateSimpleWindow(dpy, root, bar->bx + a->x + lrpad / 2, bar->by + a->y + (a->h - systray->h) / 2, MIN(a->w, 1), systray->h, 0, 0, scheme[SchemeNorm][ColBg].pixel); + XChangeWindowAttributes(dpy, systray->win, CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWEventMask, &wa); + #endif // BAR_ALPHA_PATCH + + XSelectInput(dpy, systray->win, SubstructureNotifyMask); + XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, + PropModeReplace, (unsigned char *)&systrayorientation, 1); + #if BAR_ALPHA_PATCH + XChangeProperty(dpy, systray->win, netatom[NetSystemTrayVisual], XA_VISUALID, 32, + PropModeReplace, (unsigned char *)&visual->visualid, 1); + #endif // BAR_ALPHA_PATCH + XChangeProperty(dpy, systray->win, netatom[NetWMWindowType], XA_ATOM, 32, + PropModeReplace, (unsigned char *)&netatom[NetWMWindowTypeDock], 1); + XMapRaised(dpy, systray->win); + XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); + if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { + sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0); + XSync(dpy, False); + } else { + fprintf(stderr, "dwm: unable to obtain system tray.\n"); + free(systray); + systray = NULL; + return 0; + } + } + + systray->bar = bar; + + wc.stack_mode = Above; + wc.sibling = bar->win; + XConfigureWindow(dpy, systray->win, CWSibling|CWStackMode, &wc); + + drw_setscheme(drw, scheme[SchemeNorm]); + for (w = 0, i = systray->icons; i; i = i->next) { + #if BAR_ALPHA_PATCH + wa.background_pixel = 0; + #else + wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; + #endif // BAR_ALPHA_PATCH + XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); + XMapRaised(dpy, i->win); + i->x = w; + XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); + w += i->w; + if (i->next) + w += systrayspacing; + if (i->mon != bar->mon) + i->mon = bar->mon; + } + + XMoveResizeWindow(dpy, systray->win, bar->bx + a->x + lrpad / 2, (w ? bar->by + a->y + (a->h - systray->h) / 2: -bar->by - a->y), MAX(w, 1), systray->h); + return w; +} + +int +click_systray(Bar *bar, Arg *arg, BarArg *a) +{ + return -1; +} + +void +removesystrayicon(Client *i) +{ + Client **ii; + + if (!showsystray || !i) + return; + for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); + if (ii) + *ii = i->next; + free(i); + drawbarwin(systray->bar); +} + +void +resizerequest(XEvent *e) +{ + XResizeRequestEvent *ev = &e->xresizerequest; + Client *i; + + if ((i = wintosystrayicon(ev->window))) { + updatesystrayicongeom(i, ev->width, ev->height); + drawbarwin(systray->bar); + } +} + +void +updatesystrayicongeom(Client *i, int w, int h) +{ + if (!systray) + return; + + int icon_height = systray->h; + if (i) { + i->h = icon_height; + if (w == h) + i->w = icon_height; + else if (h == icon_height) + i->w = w; + else + i->w = (int) ((float)icon_height * ((float)w / (float)h)); + applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); + /* force icons into the systray dimensions if they don't want to */ + if (i->h > icon_height) { + if (i->w == i->h) + i->w = icon_height; + else + i->w = (int) ((float)icon_height * ((float)i->w / (float)i->h)); + i->h = icon_height; + } + if (i->w > 2 * icon_height) + i->w = icon_height; + } +} + +void +updatesystrayiconstate(Client *i, XPropertyEvent *ev) +{ + long flags; + int code = 0; + + if (!showsystray || !systray || !i || ev->atom != xatom[XembedInfo] || + !(flags = getatomprop(i, xatom[XembedInfo]))) + return; + + if (flags & XEMBED_MAPPED && !i->tags) { + i->tags = 1; + code = XEMBED_WINDOW_ACTIVATE; + XMapRaised(dpy, i->win); + setclientstate(i, NormalState); + } + else if (!(flags & XEMBED_MAPPED) && i->tags) { + i->tags = 0; + code = XEMBED_WINDOW_DEACTIVATE; + XUnmapWindow(dpy, i->win); + setclientstate(i, WithdrawnState); + } + else + return; + sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0, + systray->win, XEMBED_EMBEDDED_VERSION); +} + +Client * +wintosystrayicon(Window w) +{ + if (!systray) + return NULL; + Client *i = NULL; + if (!showsystray || !w) + return i; + for (i = systray->icons; i && i->win != w; i = i->next); + return i; +} \ No newline at end of file diff --git a/suckless/dwm/patch/bar_systray.h b/suckless/dwm/patch/bar_systray.h new file mode 100644 index 00000000..851b3ec4 --- /dev/null +++ b/suckless/dwm/patch/bar_systray.h @@ -0,0 +1,41 @@ +#define SYSTEM_TRAY_REQUEST_DOCK 0 +#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0 + +/* XEMBED messages */ +#define XEMBED_EMBEDDED_NOTIFY 0 +#define XEMBED_WINDOW_ACTIVATE 1 +#define XEMBED_FOCUS_IN 4 +#define XEMBED_MODALITY_ON 10 + +#define XEMBED_MAPPED (1 << 0) +#define XEMBED_WINDOW_ACTIVATE 1 +#define XEMBED_WINDOW_DEACTIVATE 2 + +#define VERSION_MAJOR 0 +#define VERSION_MINOR 0 +#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR + +/* enums */ +enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ + +typedef struct Systray Systray; +struct Systray { + Window win; + Client *icons; + Bar *bar; + int h; +}; + +/* bar integration */ +static int width_systray(Bar *bar, BarArg *a); +static int draw_systray(Bar *bar, BarArg *a); +static int click_systray(Bar *bar, Arg *arg, BarArg *a); + +/* function declarations */ +static Atom getatomprop(Client *c, Atom prop); +static void removesystrayicon(Client *i); +static void resizerequest(XEvent *e); +static void updatesystrayicongeom(Client *i, int w, int h); +static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); +static Client *wintosystrayicon(Window w); + diff --git a/suckless/dwm/patch/bar_tabgroups.c b/suckless/dwm/patch/bar_tabgroups.c new file mode 100644 index 00000000..28a39fa9 --- /dev/null +++ b/suckless/dwm/patch/bar_tabgroups.c @@ -0,0 +1,220 @@ +/* Bartabgroups properties, you can override these in your config.h if you want. */ +#ifndef BARTAB_BORDERS +#define BARTAB_BORDERS 1 // 0 = off, 1 = on +#endif +#ifndef BARTAB_SHOWFLOATING +#define BARTAB_SHOWFLOATING 0 // whether to show titles for floating windows, hidden clients are always shown +#endif +#ifndef BARTAB_STACKWEIGHT +#define BARTAB_STACKWEIGHT 1 // stack weight compared to hidden and floating window titles +#endif +#ifndef BARTAB_HIDDENWEIGHT +#define BARTAB_HIDDENWEIGHT 1 // hidden window title weight +#endif +#ifndef BARTAB_FLOATWEIGHT +#define BARTAB_FLOATWEIGHT 1 // floating window title weight, set to 0 to not show floating windows +#endif + +int +width_bartabgroups(Bar *bar, BarArg *a) +{ + return a->w; +} + +int +draw_bartabgroups(Bar *bar, BarArg *a) +{ + drw_rect(drw, a->x, a->y, a->w, a->h, 1, 1); + return bartabcalculate(bar->mon, a->x, a->w, -1, bartabdraw, NULL, a); +} + +int +click_bartabgroups(Bar *bar, Arg *arg, BarArg *a) +{ + bartabcalculate(bar->mon, 0, a->w, a->x, bartabclick, arg, a); + return ClkWinTitle; +} + +void +bartabdraw(Monitor *m, Client *c, int unused, int x, int w, int groupactive, Arg *arg, BarArg *barg) +{ + if (!c) + return; + int i, nclienttags = 0, nviewtags = 0, pad = lrpad / 2; + drw_setscheme(drw, scheme[ + m->sel == c + ? SchemeSel + #ifdef HIDDEN + : HIDDEN(c) + ? SchemeHid + #endif + : groupactive + ? SchemeTitleSel + : SchemeTitleNorm + ]); + if (w <= TEXTW("A") - lrpad + pad) // reduce text padding if wintitle is too small + pad = (w - TEXTW("A") + lrpad < 0 ? 0 : (w - TEXTW("A") + lrpad) / 2); + #if BAR_CENTEREDWINDOWNAME_PATCH + else if (TEXTW(c->name) < w) + pad = (w - TEXTW(c->name) + lrpad) / 2; + #endif // BAR_CENTEREDWINDOWNAME_PATCH + + drw_text(drw, x, barg->y, w, barg->h, pad, c->name, 0, False); + drawstateindicator(m, c, 1, x, barg->y, w, barg->h, 0, 0, c->isfixed); + + if (BARTAB_BORDERS) { + XSetForeground(drw->dpy, drw->gc, scheme[SchemeSel][ColBorder].pixel); + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, barg->y, 1, barg->h); + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x + w - (x + w >= barg->w ? 1 : 0), barg->y, 1, barg->h); + } + /* Optional tags icons */ + for (i = 0; i < NUMTAGS; i++) { + if ((m->tagset[m->seltags] >> i) & 1) + nviewtags++; + if ((c->tags >> i) & 1) + nclienttags++; + } + + if (TAGSINDICATOR == 2 || nclienttags > 1 || nviewtags > 1) + drawindicator(m, c, 1, x, barg->y, w, barg->h, 0, 0, 0, INDICATOR_RIGHT_TAGS); +} + +#ifndef HIDDEN +#define HIDDEN(C) 0 +#endif + +void +bartabclick(Monitor *m, Client *c, int passx, int x, int w, int unused, Arg *arg, BarArg *barg) +{ + if (passx >= x && passx <= x + w) + arg->v = c; +} + +int +bartabcalculate( + Monitor *m, int offx, int tabw, int passx, + void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg), + Arg *arg, BarArg *barg +) { + Client *c; + int + i, clientsnmaster = 0, clientsnstack = 0, clientsnfloating = 0, clientsnhidden = 0, + masteractive = 0, fulllayout = 0, + x = offx, w, r, num = 0, den, tgactive; + + for (i = 0; i < LENGTH(bartabmonfns); i++) + if (m ->lt[m->sellt]->arrange == bartabmonfns[i]) { + fulllayout = 1; + break; + } + + for (i = 0, c = m->clients; c; c = c->next) { + if (!ISVISIBLE(c)) + continue; + if (HIDDEN(c)) { + clientsnhidden++; + continue; + } + if (c->isfloating) { + clientsnfloating++; + continue; + } + if (m->sel == c) + masteractive = i < m->nmaster; + if (i < m->nmaster) + clientsnmaster++; + else + clientsnstack++; + i++; + } + + if (clientsnmaster + clientsnstack + clientsnfloating + clientsnhidden == 0) + return 0; + + tgactive = 1; + num = tabw; + /* floating mode */ + if ((fulllayout && BARTAB_FLOATWEIGHT) || clientsnmaster + clientsnstack == 0 || !m->lt[m->sellt]->arrange) { + den = clientsnmaster + clientsnstack + clientsnfloating + clientsnhidden; + r = num % den; + w = num / den; + for (c = m->clients, i = 0; c; c = c->next) { + if (!ISVISIBLE(c)) + continue; + tabfn(m, c, passx, x, w + (i < r ? 1 : 0), tgactive, arg, barg); + x += w + (i < r ? 1 : 0); + i++; + } + /* no master and stack mode, e.g. monocole, grid layouts, fibonacci */ + } else if (fulllayout) { + den = clientsnmaster + clientsnstack + clientsnhidden; + r = num % den; + w = num / den; + for (c = m->clients, i = 0; c; c = c->next) { + if (!ISVISIBLE(c) || (c->isfloating && !HIDDEN(c))) + continue; + tabfn(m, c, passx, x, w + (i < r ? 1 : 0), tgactive, arg, barg); + x += w + (i < r ? 1 : 0); + i++; + } + /* tiled mode */ + } else { + den = clientsnmaster; + c = m->clients; + i = 0; + if (den) { + if (clientsnstack + clientsnfloating * BARTAB_FLOATWEIGHT + clientsnhidden) { + tgactive = masteractive; + num = tabw * m->mfact; + } + r = num % den; + w = num / den; + for (; c && i < m->nmaster; c = c->next) { // tiled master + if (!ISVISIBLE(c) || c->isfloating || HIDDEN(c)) + continue; + tabfn(m, c, passx, x, w + (i < r ? 1 : 0), tgactive, arg, barg); + x += w + (i < r ? 1 : 0); + i++; + } + tgactive = !tgactive; + num = tabw - num; + } + + den = clientsnstack * BARTAB_STACKWEIGHT + clientsnfloating * BARTAB_FLOATWEIGHT + clientsnhidden * BARTAB_HIDDENWEIGHT; + if (!den) + return 1; + + r = num % den; + w = num / den; + #if BARTAB_STACKWEIGHT + for (; c; c = c->next) { // tiled stack + if (!ISVISIBLE(c) || HIDDEN(c) || c->isfloating) + continue; + tabfn(m, c, passx, x, w * BARTAB_STACKWEIGHT + (i - m->nmaster < r ? 1 : 0), tgactive, arg, barg); + x += w * BARTAB_STACKWEIGHT + (i - m->nmaster < r ? 1 : 0); + i++; + } + #endif // BARTAB_STACKWEIGHT + + #if BARTAB_HIDDENWEIGHT + for (c = m->clients; c; c = c->next) { // hidden windows + if (!ISVISIBLE(c) || !HIDDEN(c)) + continue; + tabfn(m, c, passx, x, w * BARTAB_HIDDENWEIGHT + (i - m->nmaster < r ? 1 : 0), tgactive, arg, barg); + x += w * BARTAB_HIDDENWEIGHT + (i - m->nmaster < r ? 1 : 0); + i++; + } + #endif // BARTAB_HIDDENWEIGHT + + #if BARTAB_FLOATWEIGHT + for (c = m->clients; c; c = c->next) { // floating windows + if (!ISVISIBLE(c) || HIDDEN(c) || !c->isfloating) + continue; + tabfn(m, c, passx, x, w * BARTAB_FLOATWEIGHT + (i - m->nmaster < r ? 1 : 0), tgactive, arg, barg); + x += w * BARTAB_FLOATWEIGHT + (i - m->nmaster < r ? 1 : 0); + i++; + } + #endif // BARTAB_FLOATWEIGHT + } + return 1; +} \ No newline at end of file diff --git a/suckless/dwm/patch/bar_tabgroups.h b/suckless/dwm/patch/bar_tabgroups.h new file mode 100644 index 00000000..e118c0d2 --- /dev/null +++ b/suckless/dwm/patch/bar_tabgroups.h @@ -0,0 +1,7 @@ +static int width_bartabgroups(Bar *bar, BarArg *a); +static int draw_bartabgroups(Bar *bar, BarArg *a); +static int click_bartabgroups(Bar *bar, Arg *arg, BarArg *a); + +static void bartabdraw(Monitor *m, Client *c, int unused, int x, int w, int groupactive, Arg *arg, BarArg *barg); +static void bartabclick(Monitor *m, Client *c, int passx, int x, int w, int unused, Arg *arg, BarArg *barg); +static int bartabcalculate(Monitor *m, int offx, int w, int passx, void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg), Arg *arg, BarArg *barg); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_taggrid.c b/suckless/dwm/patch/bar_taggrid.c new file mode 100644 index 00000000..387f25ba --- /dev/null +++ b/suckless/dwm/patch/bar_taggrid.c @@ -0,0 +1,149 @@ +int +width_taggrid(Bar *bar, BarArg *a) +{ + return (a->h / 2) * (NUMTAGS / tagrows + ((NUMTAGS % tagrows > 0) ? 1 : 0)) + lrpad; +} + +int +draw_taggrid(Bar *bar, BarArg *a) +{ + unsigned int x, y, h, max_x = 0, columns, occ = 0; + int invert, i,j, k; + Client *c; + + for (c = bar->mon->clients; c; c = c->next) + occ |= c->tags; + + max_x = x = a->x + lrpad / 2; + h = a->h / tagrows - 1; + y = a->y; + columns = NUMTAGS / tagrows + ((NUMTAGS % tagrows > 0) ? 1 : 0); + + /* Firstly we will fill the borders of squares */ + XSetForeground(drw->dpy, drw->gc, scheme[SchemeTagsNorm][ColBg].pixel); + XFillRectangle(dpy, drw->drawable, drw->gc, x, y, h*columns + 1, a->h); + + /* We will draw NUMTAGS squares in tagraws raws. */ + for (j = 0, i = 0; j < tagrows; j++) { + x = a->x + lrpad / 2; + for (k = 0; k < columns; k++, i++) { + if (i < NUMTAGS) { + invert = bar->mon->tagset[bar->mon->seltags] & 1 << i ? 0 : 1; + + /* Select active color for current square */ + XSetForeground(drw->dpy, drw->gc, !invert ? scheme[SchemeTagsSel][ColBg].pixel : + scheme[SchemeTagsNorm][ColFg].pixel); + XFillRectangle(dpy, drw->drawable, drw->gc, x+1, y+1, h-1, h-1); + + /* Mark square if tag has client */ + if (occ & 1 << i) { + XSetForeground(drw->dpy, drw->gc, !invert ? scheme[SchemeTagsSel][ColFg].pixel : + scheme[SchemeTagsNorm][ColBg].pixel); + XFillRectangle(dpy, drw->drawable, drw->gc, x + 1, y + 1, + h / 2, h / 2); + } + } else { + XSetForeground(drw->dpy, drw->gc, scheme[SchemeTagsNorm][ColBg].pixel); + XFillRectangle(dpy, drw->drawable, drw->gc, x+1, y+1, h-1, h); + } + x += h; + if (x > max_x) { + max_x = x; + } + } + y += h; + } + return 1; +} + +int +click_taggrid(Bar *bar, Arg *arg, BarArg *a) +{ + unsigned int i, h, columns; + + h = a->h / tagrows - 1; + columns = NUMTAGS / tagrows + ((NUMTAGS % tagrows > 0) ? 1 : 0); + i = (a->x - lrpad / 2) / h + columns * (a->y / h); + if (i >= NUMTAGS) { + i = NUMTAGS - 1; + } + arg->ui = 1 << i; + return ClkTagBar; +} + +void +switchtag(const Arg *arg) +{ + unsigned int columns; + unsigned int new_tagset = 0; + unsigned int pos, i; + int col, row; + Arg new_arg; + + columns = NUMTAGS / tagrows + ((NUMTAGS % tagrows > 0) ? 1 : 0); + + for (i = 0; i < NUMTAGS; ++i) { + if (!(selmon->tagset[selmon->seltags] & 1 << i)) { + continue; + } + pos = i; + row = pos / columns; + col = pos % columns; + if (arg->ui & SWITCHTAG_UP) { /* UP */ + row --; + if (row < 0) { + row = tagrows - 1; + } + do { + pos = row * columns + col; + row --; + } while (pos >= NUMTAGS); + } + if (arg->ui & SWITCHTAG_DOWN) { /* DOWN */ + row ++; + if (row >= tagrows) { + row = 0; + } + pos = row * columns + col; + if (pos >= NUMTAGS) { + row = 0; + } + pos = row * columns + col; + } + if (arg->ui & SWITCHTAG_LEFT) { /* LEFT */ + col --; + if (col < 0) { + col = columns - 1; + } + do { + pos = row * columns + col; + col --; + } while (pos >= NUMTAGS); + } + if (arg->ui & SWITCHTAG_RIGHT) { /* RIGHT */ + col ++; + if (col >= columns) { + col = 0; + } + pos = row * columns + col; + if (pos >= NUMTAGS) { + col = 0; + pos = row * columns + col; + } + } + new_tagset |= 1 << pos; + } + new_arg.ui = new_tagset; + if (arg->ui & SWITCHTAG_TOGGLETAG) { + toggletag(&new_arg); + } + if (arg->ui & SWITCHTAG_TAG) { + tag(&new_arg); + } + if (arg->ui & SWITCHTAG_VIEW) { + view (&new_arg); + } + if (arg->ui & SWITCHTAG_TOGGLEVIEW) { + toggleview (&new_arg); + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/bar_taggrid.h b/suckless/dwm/patch/bar_taggrid.h new file mode 100644 index 00000000..e0c824e8 --- /dev/null +++ b/suckless/dwm/patch/bar_taggrid.h @@ -0,0 +1,4 @@ +static int width_taggrid(Bar *bar, BarArg *a); +static int draw_taggrid(Bar *bar, BarArg *a); +static int click_taggrid(Bar *bar, Arg *arg, BarArg *a); +static void switchtag(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_tagicons.c b/suckless/dwm/patch/bar_tagicons.c new file mode 100644 index 00000000..d472407c --- /dev/null +++ b/suckless/dwm/patch/bar_tagicons.c @@ -0,0 +1,20 @@ +char * +tagicon(Monitor *m, int tag) +{ + #if BAR_ALTTAGSDECORATION_PATCH + Client *c; + #endif // BAR_ALTTAGSDECORATION_PATCH + int tagindex = tag + NUMTAGS * m->index; + if (tagindex >= LENGTH(tagicons[DEFAULT_TAGS])) + tagindex = tagindex % LENGTH(tagicons[DEFAULT_TAGS]); + #if BAR_ALTTAGSDECORATION_PATCH + for (c = m->clients; c && (!(c->tags & 1 << tag) || HIDDEN(c)); c = c->next); + if (c) + return tagicons[ALT_TAGS_DECORATION][tagindex]; + #endif // BAR_ALTTAGSDECORATION_PATCH + #if BAR_ALTERNATIVE_TAGS_PATCH + if (m->alttag) + return tagicons[ALTERNATIVE_TAGS][tagindex]; + #endif // BAR_ALTERNATIVE_TAGS_PATCH + return tagicons[DEFAULT_TAGS][tagindex]; +} \ No newline at end of file diff --git a/suckless/dwm/patch/bar_tagicons.h b/suckless/dwm/patch/bar_tagicons.h new file mode 100644 index 00000000..be5d35c9 --- /dev/null +++ b/suckless/dwm/patch/bar_tagicons.h @@ -0,0 +1,7 @@ +enum { + DEFAULT_TAGS, + ALTERNATIVE_TAGS, + ALT_TAGS_DECORATION, +}; + +static char * tagicon(Monitor *m, int tag); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_tags.c b/suckless/dwm/patch/bar_tags.c new file mode 100644 index 00000000..df83144f --- /dev/null +++ b/suckless/dwm/patch/bar_tags.c @@ -0,0 +1,88 @@ +int +width_tags(Bar *bar, BarArg *a) +{ + int w, i; + #if BAR_HIDEVACANTTAGS_PATCH + Client *c; + unsigned int occ = 0; + for (c = bar->mon->clients; c; c = c->next) + occ |= c->tags == 255 ? 0 : c->tags; + #endif // BAR_HIDEVACANTTAGS_PATCH + + for (w = 0, i = 0; i < NUMTAGS; i++) { + #if BAR_HIDEVACANTTAGS_PATCH + if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i)) + continue; + #endif // BAR_HIDEVACANTTAGS_PATCH + w += TEXTW(tagicon(bar->mon, i)); + } + return w; +} + +int +draw_tags(Bar *bar, BarArg *a) +{ + int invert; + int w, x = a->x; + unsigned int i, occ = 0, urg = 0; + char *icon; + Client *c; + Monitor *m = bar->mon; + + for (c = m->clients; c; c = c->next) { + #if BAR_HIDEVACANTTAGS_PATCH + occ |= c->tags == 255 ? 0 : c->tags; + #else + occ |= c->tags; + #endif // BAR_HIDEVACANTTAGS_PATCH + if (c->isurgent) + urg |= c->tags; + } + for (i = 0; i < NUMTAGS; i++) { + #if BAR_HIDEVACANTTAGS_PATCH + /* do not draw vacant tags */ + if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) + continue; + #endif // BAR_HIDEVACANTTAGS_PATCH + + icon = tagicon(bar->mon, i); + invert = 0; + w = TEXTW(icon); + drw_setscheme(drw, scheme[ + m->tagset[m->seltags] & 1 << i + ? SchemeTagsSel + : urg & 1 << i + ? SchemeUrg + : SchemeTagsNorm + ]); + drw_text(drw, x, a->y, w, a->h, lrpad / 2, icon, invert, False); + drawindicator(m, NULL, occ, x, a->y, w, a->h, i, -1, invert, tagindicatortype); + x += w; + } + + return 1; +} + +int +click_tags(Bar *bar, Arg *arg, BarArg *a) +{ + int i = 0, x = lrpad / 2; + #if BAR_HIDEVACANTTAGS_PATCH + Client *c; + unsigned int occ = 0; + for (c = bar->mon->clients; c; c = c->next) + occ |= c->tags == 255 ? 0 : c->tags; + #endif // BAR_HIDEVACANTTAGS_PATCH + + do { + #if BAR_HIDEVACANTTAGS_PATCH + if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i)) + continue; + #endif // BAR_HIDEVACANTTAGS_PATCH + x += TEXTW(tagicon(bar->mon, i)); + } while (a->x >= x && ++i < NUMTAGS); + if (i < NUMTAGS) { + arg->ui = 1 << i; + } + return ClkTagBar; +} diff --git a/suckless/dwm/patch/bar_tags.h b/suckless/dwm/patch/bar_tags.h new file mode 100644 index 00000000..9ab784b7 --- /dev/null +++ b/suckless/dwm/patch/bar_tags.h @@ -0,0 +1,3 @@ +static int width_tags(Bar *bar, BarArg *a); +static int draw_tags(Bar *bar, BarArg *a); +static int click_tags(Bar *bar, Arg *arg, BarArg *a); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_vtcolors.c b/suckless/dwm/patch/bar_vtcolors.c new file mode 100644 index 00000000..2002985f --- /dev/null +++ b/suckless/dwm/patch/bar_vtcolors.c @@ -0,0 +1,68 @@ +void +get_vt_colors(void) +{ + char *cfs[3] = { + "/sys/module/vt/parameters/default_red", + "/sys/module/vt/parameters/default_grn", + "/sys/module/vt/parameters/default_blu", + }; + char vtcs[16][8]; + char tk[] = ","; + char cl[64]; + char *tp = NULL; + FILE *fp; + size_t r; + int i, c, n, len; + for (i = 0; i < 16; i++) + strcpy(vtcs[i], "#000000"); + + for (i = 0, r = 0; i < 3; i++) { + if ((fp = fopen(cfs[i], "r")) == NULL) + continue; + while ((cl[r] = fgetc(fp)) != EOF && cl[r] != '\n') + r++; + cl[r] = '\0'; + for (c = 0, tp = cl, n = 0; c < 16; c++, tp++) { + if ((r = strcspn(tp, tk)) == -1) + break; + for (n = 0; r && *tp >= 48 && *tp < 58; r--, tp++) + n = n * 10 - 48 + *tp; + vtcs[c][i * 2 + 1] = n / 16 < 10 ? n / 16 + 48 : n / 16 + 87; + vtcs[c][i * 2 + 2] = n % 16 < 10 ? n % 16 + 48 : n % 16 + 87; + } + fclose(fp); + } + + len = LENGTH(colors); + if (len > LENGTH(color_ptrs)) + len = LENGTH(color_ptrs); + for (i = 0; i < len; i++) { + for (c = 0; c < ColCount; c++) { + n = color_ptrs[i][c]; + if (n > -1 && strlen(colors[i][c]) >= strlen(vtcs[n])) + memcpy(colors[i][c], vtcs[n], 7); + } + } +} + +int get_luminance(char *r) +{ + char *c = r; + int n[3] = {0}; + int i = 0; + + while (*c) { + if (*c >= 48 && *c < 58) + n[i / 2] = n[i / 2] * 16 - 48 + *c; + else if (*c >= 65 && *c < 71) + n[i / 2] = n[i / 2] * 16 - 55 + *c; + else if (*c >= 97 && *c < 103) + n[i / 2] = n[i / 2] * 16 - 87 + *c; + else + i--; + i++; + c++; + } + + return (0.299 * n[0] + 0.587 * n[1] + 0.114 * n[2]) / 2.55; +} \ No newline at end of file diff --git a/suckless/dwm/patch/bar_vtcolors.h b/suckless/dwm/patch/bar_vtcolors.h new file mode 100644 index 00000000..7341e6a4 --- /dev/null +++ b/suckless/dwm/patch/bar_vtcolors.h @@ -0,0 +1,2 @@ +static void get_vt_colors(void); +static int get_luminance(char *rgb); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_wintitle.c b/suckless/dwm/patch/bar_wintitle.c new file mode 100644 index 00000000..1e9fb772 --- /dev/null +++ b/suckless/dwm/patch/bar_wintitle.c @@ -0,0 +1,51 @@ +int +width_wintitle(Bar *bar, BarArg *a) +{ + return a->w; +} + +int +draw_wintitle(Bar *bar, BarArg *a) +{ + #if BAR_TITLE_LEFT_PAD_PATCH && BAR_TITLE_RIGHT_PAD_PATCH + int x = a->x + lrpad / 2, w = a->w - lrpad; + #elif BAR_TITLE_LEFT_PAD_PATCH + int x = a->x + lrpad / 2, w = a->w - lrpad / 2; + #elif BAR_TITLE_RIGHT_PAD_PATCH + int x = a->x, w = a->w - lrpad / 2; + #else + int x = a->x, w = a->w; + #endif // BAR_TITLE_LEFT_PAD_PATCH | BAR_TITLE_RIGHT_PAD_PATCH + Monitor *m = bar->mon; + int pad = lrpad / 2; + + if (!m->sel) { + drw_setscheme(drw, scheme[SchemeTitleNorm]); + drw_rect(drw, x, a->y, w, a->h, 1, 1); + return 0; + } + + drw_setscheme(drw, scheme[m == selmon ? SchemeTitleSel : SchemeTitleNorm]); + #if BAR_IGNORE_XFT_ERRORS_WHEN_DRAWING_TEXT_PATCH + XSetErrorHandler(xerrordummy); + #endif // BAR_IGNORE_XFT_ERRORS_WHEN_DRAWING_TEXT_PATCH + #if BAR_CENTEREDWINDOWNAME_PATCH + if (TEXTW(m->sel->name) < w) + pad = (w - TEXTW(m->sel->name) + lrpad) / 2; + #endif // BAR_CENTEREDWINDOWNAME_PATCH + drw_text(drw, x, a->y, w, a->h, pad, m->sel->name, 0, False); + #if BAR_IGNORE_XFT_ERRORS_WHEN_DRAWING_TEXT_PATCH + XSync(dpy, False); + XSetErrorHandler(xerror); + #endif // BAR_IGNORE_XFT_ERRORS_WHEN_DRAWING_TEXT_PATCH + drawstateindicator(m, m->sel, 1, x, a->y, w, a->h, 0, 0, m->sel->isfixed); + return 1; +} + +int +click_wintitle(Bar *bar, Arg *arg, BarArg *a) +{ + return ClkWinTitle; +} + + diff --git a/suckless/dwm/patch/bar_wintitle.h b/suckless/dwm/patch/bar_wintitle.h new file mode 100644 index 00000000..349f948f --- /dev/null +++ b/suckless/dwm/patch/bar_wintitle.h @@ -0,0 +1,3 @@ +static int width_wintitle(Bar *bar, BarArg *a); +static int draw_wintitle(Bar *bar, BarArg *a); +static int click_wintitle(Bar *bar, Arg *arg, BarArg *a); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_wintitle_floating.c b/suckless/dwm/patch/bar_wintitle_floating.c new file mode 100644 index 00000000..001486b5 --- /dev/null +++ b/suckless/dwm/patch/bar_wintitle_floating.c @@ -0,0 +1,45 @@ +int +width_wintitle_floating(Bar *bar, BarArg *a) +{ + return a->w; +} + +int +draw_wintitle_floating(Bar *bar, BarArg *a) +{ + drw_rect(drw, a->x, a->y, a->w, a->h, 1, 1); + return calc_wintitle_floating(bar->mon, a->x, a->w, -1, flextitledraw, NULL, a); +} + +int +click_wintitle_floating(Bar *bar, Arg *arg, BarArg *a) +{ + calc_wintitle_floating(bar->mon, 0, a->w, a->x, flextitleclick, arg, a); + return ClkWinTitle; +} + +int +calc_wintitle_floating( + Monitor *m, int offx, int tabw, int passx, + void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg), + Arg *arg, BarArg *barg +) { + Client *c; + int clientsnfloating = 0, w, r; + int groupactive = GRP_FLOAT; + + for (c = m->clients; c; c = c->next) { + if (!ISVISIBLE(c) || HIDDEN(c)) + continue; + if (c->isfloating) + clientsnfloating++; + } + + if (!clientsnfloating) + return 0; + + w = tabw / clientsnfloating; + r = tabw % clientsnfloating; + c = flextitledrawarea(m, m->clients, offx, r, w, clientsnfloating, SCHEMEFOR(GRP_FLOAT), 0, 0, 1, passx, tabfn, arg, barg); + return 1; +} \ No newline at end of file diff --git a/suckless/dwm/patch/bar_wintitle_floating.h b/suckless/dwm/patch/bar_wintitle_floating.h new file mode 100644 index 00000000..d04569ca --- /dev/null +++ b/suckless/dwm/patch/bar_wintitle_floating.h @@ -0,0 +1,8 @@ +static int width_wintitle_floating(Bar *bar, BarArg *a); +static int draw_wintitle_floating(Bar *bar, BarArg *a); +static int click_wintitle_floating(Bar *bar, Arg *arg, BarArg *a); +static int calc_wintitle_floating( + Monitor *m, int offx, int tabw, int passx, + void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg), + Arg *arg, BarArg *barg +); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_wintitle_hidden.c b/suckless/dwm/patch/bar_wintitle_hidden.c new file mode 100644 index 00000000..1fa12bc7 --- /dev/null +++ b/suckless/dwm/patch/bar_wintitle_hidden.c @@ -0,0 +1,45 @@ +int +width_wintitle_hidden(Bar *bar, BarArg *a) +{ + return a->w; +} + +int +draw_wintitle_hidden(Bar *bar, BarArg *a) +{ + drw_rect(drw, a->x, a->y, a->w, a->h, 1, 1); + return calc_wintitle_hidden(bar->mon, a->x, a->w, -1, flextitledraw, NULL, a); +} + +int +click_wintitle_hidden(Bar *bar, Arg *arg, BarArg *a) +{ + calc_wintitle_hidden(bar->mon, 0, a->w, a->x, flextitleclick, arg, a); + return ClkWinTitle; +} + +int +calc_wintitle_hidden( + Monitor *m, int offx, int tabw, int passx, + void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg), + Arg *arg, BarArg *barg +) { + Client *c; + int clientsnhidden = 0, w, r; + int groupactive = GRP_HIDDEN; + + for (c = m->clients; c; c = c->next) { + if (!ISVISIBLE(c)) + continue; + if (HIDDEN(c)) + clientsnhidden++; + } + + if (!clientsnhidden) + return 0; + + w = tabw / clientsnhidden; + r = tabw % clientsnhidden; + c = flextitledrawarea(m, m->clients, offx, r, w, clientsnhidden, SCHEMEFOR(GRP_HIDDEN), 0, 1, 0, passx, tabfn, arg, barg); + return 1; +} \ No newline at end of file diff --git a/suckless/dwm/patch/bar_wintitle_hidden.h b/suckless/dwm/patch/bar_wintitle_hidden.h new file mode 100644 index 00000000..e757391d --- /dev/null +++ b/suckless/dwm/patch/bar_wintitle_hidden.h @@ -0,0 +1,8 @@ +static int width_wintitle_hidden(Bar *bar, BarArg *a); +static int draw_wintitle_hidden(Bar *bar, BarArg *a); +static int click_wintitle_hidden(Bar *bar, Arg *arg, BarArg *a); +static int calc_wintitle_hidden( + Monitor *m, int offx, int tabw, int passx, + void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg), + Arg *arg, BarArg *barg +); \ No newline at end of file diff --git a/suckless/dwm/patch/bar_wintitleactions.c b/suckless/dwm/patch/bar_wintitleactions.c new file mode 100644 index 00000000..e94fe067 --- /dev/null +++ b/suckless/dwm/patch/bar_wintitleactions.c @@ -0,0 +1,93 @@ +void +hide(Client *c) { + + Client *n; + if (!c || HIDDEN(c)) + return; + + Window w = c->win; + static XWindowAttributes ra, ca; + + // more or less taken directly from blackbox's hide() function + XGrabServer(dpy); + XGetWindowAttributes(dpy, root, &ra); + XGetWindowAttributes(dpy, w, &ca); + // prevent UnmapNotify events + XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask); + XSelectInput(dpy, w, ca.your_event_mask & ~StructureNotifyMask); + XUnmapWindow(dpy, w); + setclientstate(c, IconicState); + XSelectInput(dpy, root, ra.your_event_mask); + XSelectInput(dpy, w, ca.your_event_mask); + XUngrabServer(dpy); + + if (c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { + for (n = c->snext; n && (!ISVISIBLE(n) || HIDDEN(n)); n = n->snext); + if (!n) + for (n = c->mon->stack; n && (!ISVISIBLE(n) || HIDDEN(n)); n = n->snext); + } else { + n = nexttiled(c); + if (!n) + n = prevtiled(c); + } + focus(n); + arrange(c->mon); +} + +void +show(Client *c) +{ + if (!c || !HIDDEN(c)) + return; + + XMapWindow(dpy, c->win); + setclientstate(c, NormalState); + arrange(c->mon); +} + +void +togglewin(const Arg *arg) +{ + Client *c = (Client*)arg->v; + if (!c) + return; + if (c == selmon->sel) + hide(c); + else { + if (HIDDEN(c)) + show(c); + focus(c); + restack(c->mon); + } +} + +Client * +prevtiled(Client *c) +{ + Client *p, *i; + for (p = NULL, i = c->mon->clients; c && i != c; i = i->next) + if (ISVISIBLE(i) && !HIDDEN(i)) + p = i; + return p; +} + +void +showhideclient(const Arg *arg) +{ + Client *c = (Client*)arg->v; + if (!c) + c = selmon->sel; + if (!c) + return; + + #if WARP_PATCH + force_warp = 1; + #endif // WARP_PATCH + if (HIDDEN(c)) { + show(c); + focus(c); + restack(c->mon); + } else { + hide(c); + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/bar_wintitleactions.h b/suckless/dwm/patch/bar_wintitleactions.h new file mode 100644 index 00000000..67a9d791 --- /dev/null +++ b/suckless/dwm/patch/bar_wintitleactions.h @@ -0,0 +1,5 @@ +static void hide(Client *c); +static void show(Client *c); +static void togglewin(const Arg *arg); +static Client * prevtiled(Client *c); +static void showhideclient(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/cfacts.c b/suckless/dwm/patch/cfacts.c new file mode 100644 index 00000000..ece210f4 --- /dev/null +++ b/suckless/dwm/patch/cfacts.c @@ -0,0 +1,23 @@ +void +setcfact(const Arg *arg) +{ + float f; + Client *c; + + c = selmon->sel; + + if (!arg || !c || !selmon->lt[selmon->sellt]->arrange) + return; + if (!arg->f) + f = 1.0; + else if (arg->f > 4.0) // set fact absolutely + f = arg->f - 4.0; + else + f = arg->f + c->cfact; + if (f < 0.25) + f = 0.25; + else if (f > 4.0) + f = 4.0; + c->cfact = f; + arrange(selmon); +} \ No newline at end of file diff --git a/suckless/dwm/patch/cfacts.h b/suckless/dwm/patch/cfacts.h new file mode 100644 index 00000000..b8d8b041 --- /dev/null +++ b/suckless/dwm/patch/cfacts.h @@ -0,0 +1 @@ +static void setcfact(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/cmdcustomize.c b/suckless/dwm/patch/cmdcustomize.c new file mode 100644 index 00000000..1e62d205 --- /dev/null +++ b/suckless/dwm/patch/cmdcustomize.c @@ -0,0 +1,5 @@ +char* +help(void) +{ + return "usage: dwm [-hv] [-fn font] [-nb color] [-nf color] [-sb color] [-sf color]\n[-df font] [-dnf color] [-dnb color] [-dsf color] [-dsb color]\n"; +} \ No newline at end of file diff --git a/suckless/dwm/patch/cmdcustomize.h b/suckless/dwm/patch/cmdcustomize.h new file mode 100644 index 00000000..280f5b87 --- /dev/null +++ b/suckless/dwm/patch/cmdcustomize.h @@ -0,0 +1 @@ +static char* help(); \ No newline at end of file diff --git a/suckless/dwm/patch/combo.c b/suckless/dwm/patch/combo.c new file mode 100644 index 00000000..43f7e5d4 --- /dev/null +++ b/suckless/dwm/patch/combo.c @@ -0,0 +1,49 @@ +static int combo = 0; + +#if !BAR_HOLDBAR_PATCH +void +keyrelease(XEvent *e) +{ + combo = 0; +} +#endif // !BAR_HOLDBAR_PATCH + +void +combotag(const Arg *arg) +{ + if (selmon->sel && arg->ui & TAGMASK) { + #if SWITCHTAG_PATCH + if (selmon->sel->switchtag) + selmon->sel->switchtag = 0; + #endif // SWITCHTAG_PATCH + if (combo) { + selmon->sel->tags |= arg->ui & TAGMASK; + } else { + combo = 1; + selmon->sel->tags = arg->ui & TAGMASK; + } + focus(NULL); + arrange(selmon); + } +} + +void +comboview(const Arg *arg) +{ + unsigned newtags = arg->ui & TAGMASK; + if (combo) { + selmon->tagset[selmon->seltags] |= newtags; + } else { + selmon->seltags ^= 1; /*toggle tagset*/ + combo = 1; + if (newtags) { + #if PERTAG_PATCH + pertagview(&((Arg) { .ui = newtags })); + #else + selmon->tagset[selmon->seltags] = newtags; + #endif // PERTAG_PATCH + } + } + focus(NULL); + arrange(selmon); +} \ No newline at end of file diff --git a/suckless/dwm/patch/combo.h b/suckless/dwm/patch/combo.h new file mode 100644 index 00000000..752f6363 --- /dev/null +++ b/suckless/dwm/patch/combo.h @@ -0,0 +1,5 @@ +#if !BAR_HOLDBAR_PATCH +static void keyrelease(XEvent *e); +#endif // !BAR_HOLDBAR_PATCH +static void combotag(const Arg *arg); +static void comboview(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/cool_autostart.c b/suckless/dwm/patch/cool_autostart.c new file mode 100644 index 00000000..2bc3c3b4 --- /dev/null +++ b/suckless/dwm/patch/cool_autostart.c @@ -0,0 +1,28 @@ +/* dwm will keep pid's of processes from autostart array and kill them at quit */ +static pid_t *autostart_pids; +static size_t autostart_len; + +/* execute command from autostart array */ +static void +autostart_exec() +{ + const char *const *p; + size_t i = 0; + + /* count entries */ + for (p = autostart; *p; autostart_len++, p++) + while (*++p); + + autostart_pids = malloc(autostart_len * sizeof(pid_t)); + for (p = autostart; *p; i++, p++) { + if ((autostart_pids[i] = fork()) == 0) { + setsid(); + execvp(*p, (char *const *)p); + fprintf(stderr, "dwm: execvp %s\n", *p); + perror(" failed"); + _exit(EXIT_FAILURE); + } + /* skip arguments */ + while (*++p); + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/cool_autostart.h b/suckless/dwm/patch/cool_autostart.h new file mode 100644 index 00000000..8dc0d192 --- /dev/null +++ b/suckless/dwm/patch/cool_autostart.h @@ -0,0 +1 @@ +static void autostart_exec(void); \ No newline at end of file diff --git a/suckless/dwm/patch/cyclelayouts.c b/suckless/dwm/patch/cyclelayouts.c new file mode 100644 index 00000000..bd33bfe8 --- /dev/null +++ b/suckless/dwm/patch/cyclelayouts.c @@ -0,0 +1,17 @@ +void +cyclelayout(const Arg *arg) +{ + Layout *l; + for (l = (Layout *)layouts; l != selmon->lt[selmon->sellt]; l++); + if (arg->i > 0) { + if (l->symbol && (l + 1)->symbol) + setlayout(&((Arg) { .v = (l + 1) })); + else + setlayout(&((Arg) { .v = layouts })); + } else { + if (l != layouts && (l - 1)->symbol) + setlayout(&((Arg) { .v = (l - 1) })); + else + setlayout(&((Arg) { .v = &layouts[LENGTH(layouts) - 2] })); + } +} diff --git a/suckless/dwm/patch/cyclelayouts.h b/suckless/dwm/patch/cyclelayouts.h new file mode 100644 index 00000000..02c5f9d0 --- /dev/null +++ b/suckless/dwm/patch/cyclelayouts.h @@ -0,0 +1 @@ +static void cyclelayout(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/decorationhints.c b/suckless/dwm/patch/decorationhints.c new file mode 100644 index 00000000..66369983 --- /dev/null +++ b/suckless/dwm/patch/decorationhints.c @@ -0,0 +1,38 @@ +static Atom motifatom; + +void +updatemotifhints(Client *c) +{ + Atom real; + int format; + unsigned char *p = NULL; + unsigned long n, extra; + unsigned long *motif; + int width, height; + + if (!decorhints) + return; + + if (XGetWindowProperty(dpy, c->win, motifatom, 0L, 5L, False, motifatom, + &real, &format, &n, &extra, &p) == Success && p != NULL) { + motif = (unsigned long*)p; + if (motif[MWM_HINTS_FLAGS_FIELD] & MWM_HINTS_DECORATIONS) { + width = WIDTH(c); + height = HEIGHT(c); + + if (motif[MWM_HINTS_DECORATIONS_FIELD] & MWM_DECOR_ALL || + motif[MWM_HINTS_DECORATIONS_FIELD] & MWM_DECOR_BORDER || + motif[MWM_HINTS_DECORATIONS_FIELD] & MWM_DECOR_TITLE) + #if SETBORDERPX_PATCH + c->bw = c->oldbw = c->mon->borderpx; + #else + c->bw = c->oldbw = borderpx; + #endif // SETBORDERPX_PATCH + else + c->bw = c->oldbw = 0; + + resize(c, c->x, c->y, width - (2*c->bw), height - (2*c->bw), 0); + } + XFree(p); + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/decorationhints.h b/suckless/dwm/patch/decorationhints.h new file mode 100644 index 00000000..3a9c641c --- /dev/null +++ b/suckless/dwm/patch/decorationhints.h @@ -0,0 +1,8 @@ +#define MWM_HINTS_FLAGS_FIELD 0 +#define MWM_HINTS_DECORATIONS_FIELD 2 +#define MWM_HINTS_DECORATIONS (1 << 1) +#define MWM_DECOR_ALL (1 << 0) +#define MWM_DECOR_BORDER (1 << 1) +#define MWM_DECOR_TITLE (1 << 3) + +static void updatemotifhints(Client *c); \ No newline at end of file diff --git a/suckless/dwm/patch/dragcfact.c b/suckless/dwm/patch/dragcfact.c new file mode 100644 index 00000000..fce5c92d --- /dev/null +++ b/suckless/dwm/patch/dragcfact.c @@ -0,0 +1,82 @@ +void +dragcfact(const Arg *arg) +{ + int prev_x, prev_y, dist_x, dist_y; + float fact; + Client *c; + XEvent ev; + Time lasttime = 0; + + if (!(c = selmon->sel)) + return; + if (c->isfloating) { + resizemouse(arg); + return; + } + #if !FAKEFULLSCREEN_PATCH + #if FAKEFULLSCREEN_CLIENT_PATCH + if (c->isfullscreen && !c->fakefullscreen) /* no support resizing fullscreen windows by mouse */ + return; + #else + if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ + return; + #endif // FAKEFULLSCREEN_CLIENT_PATCH + #endif // !FAKEFULLSCREEN_PATCH + restack(selmon); + + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, + None, cursor[CurIronCross]->cursor, CurrentTime) != GrabSuccess) + return; + + #if WARP_PATCH + ignore_warp = 1; + #endif // WARP_PATCH + + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2); + + prev_x = prev_y = -999999; + + do { + XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); + switch(ev.type) { + case ConfigureRequest: + case Expose: + case MapRequest: + handler[ev.type](&ev); + break; + case MotionNotify: + if ((ev.xmotion.time - lasttime) <= (1000 / 60)) + continue; + lasttime = ev.xmotion.time; + if (prev_x == -999999) { + prev_x = ev.xmotion.x_root; + prev_y = ev.xmotion.y_root; + } + + dist_x = ev.xmotion.x - prev_x; + dist_y = ev.xmotion.y - prev_y; + + if (abs(dist_x) > abs(dist_y)) { + fact = (float) 4.0 * dist_x / c->mon->ww; + } else { + fact = (float) -4.0 * dist_y / c->mon->wh; + } + + if (fact) + setcfact(&((Arg) { .f = fact })); + + prev_x = ev.xmotion.x; + prev_y = ev.xmotion.y; + break; + } + } while (ev.type != ButtonRelease); + + #if WARP_PATCH + ignore_warp = 0; + #endif // WARP_PATCH + + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2); + + XUngrabPointer(dpy, CurrentTime); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); +} \ No newline at end of file diff --git a/suckless/dwm/patch/dragcfact.h b/suckless/dwm/patch/dragcfact.h new file mode 100644 index 00000000..6cf6b9c0 --- /dev/null +++ b/suckless/dwm/patch/dragcfact.h @@ -0,0 +1 @@ +static void dragcfact(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/dragmfact.c b/suckless/dwm/patch/dragmfact.c new file mode 100644 index 00000000..257b5c1f --- /dev/null +++ b/suckless/dwm/patch/dragmfact.c @@ -0,0 +1,231 @@ +void +dragmfact(const Arg *arg) +{ + unsigned int n; + int py, px; // pointer coordinates + int ax, ay, aw, ah; // area position, width and height + int center = 0, horizontal = 0, mirror = 0, fixed = 0; // layout configuration + double fact; + Monitor *m; + XEvent ev; + Time lasttime = 0; + + m = selmon; + + #if VANITYGAPS_PATCH + int oh, ov, ih, iv; + getgaps(m, &oh, &ov, &ih, &iv, &n); + #else + Client *c; + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + #endif // VANITYGAPS_PATCH + + ax = m->wx; + ay = m->wy; + ah = m->wh; + aw = m->ww; + + if (!n) + return; + #if FLEXTILE_DELUXE_LAYOUT + else if (m->lt[m->sellt]->arrange == &flextile) { + int layout = m->ltaxis[LAYOUT]; + if (layout < 0) { + mirror = 1; + layout *= -1; + } + if (layout > FLOATING_MASTER) { + layout -= FLOATING_MASTER; + fixed = 1; + } + + if (layout == SPLIT_HORIZONTAL || layout == SPLIT_HORIZONTAL_DUAL_STACK) + horizontal = 1; + else if (layout == SPLIT_CENTERED_VERTICAL && (fixed || n - m->nmaster > 1)) + center = 1; + else if (layout == FLOATING_MASTER) { + center = 1; + if (aw < ah) + horizontal = 1; + } + else if (layout == SPLIT_CENTERED_HORIZONTAL) { + if (fixed || n - m->nmaster > 1) + center = 1; + horizontal = 1; + } + } + #endif // FLEXTILE_DELUXE_LAYOUT + #if CENTEREDMASTER_LAYOUT + else if (m->lt[m->sellt]->arrange == ¢eredmaster && (fixed || n - m->nmaster > 1)) + center = 1; + #endif // CENTEREDMASTER_LAYOUT + #if CENTEREDFLOATINGMASTER_LAYOUT + else if (m->lt[m->sellt]->arrange == ¢eredfloatingmaster) + center = 1; + #endif // CENTEREDFLOATINGMASTER_LAYOUT + #if BSTACK_LAYOUT + else if (m->lt[m->sellt]->arrange == &bstack) + horizontal = 1; + #endif // BSTACK_LAYOUT + #if BSTACKHORIZ_LAYOUT + else if (m->lt[m->sellt]->arrange == &bstackhoriz) + horizontal = 1; + #endif // BSTACKHORIZ_LAYOUT + + /* do not allow mfact to be modified under certain conditions */ + if (!m->lt[m->sellt]->arrange // floating layout + || (!fixed && m->nmaster && n <= m->nmaster) // no master + #if MONOCLE_LAYOUT + || m->lt[m->sellt]->arrange == &monocle + #endif // MONOCLE_LAYOUT + #if GRIDMODE_LAYOUT + || m->lt[m->sellt]->arrange == &grid + #endif // GRIDMODE_LAYOUT + #if HORIZGRID_LAYOUT + || m->lt[m->sellt]->arrange == &horizgrid + #endif // HORIZGRID_LAYOUT + #if GAPPLESSGRID_LAYOUT + || m->lt[m->sellt]->arrange == &gaplessgrid + #endif // GAPPLESSGRID_LAYOUT + #if NROWGRID_LAYOUT + || m->lt[m->sellt]->arrange == &nrowgrid + #endif // NROWGRID_LAYOUT + #if FLEXTILE_DELUXE_LAYOUT + || (m->lt[m->sellt]->arrange == &flextile && m->ltaxis[LAYOUT] == NO_SPLIT) + #endif // FLEXTILE_DELUXE_LAYOUT + ) + return; + + #if VANITYGAPS_PATCH + ay += oh; + ax += ov; + aw -= 2*ov; + ah -= 2*oh; + #endif // VANITYGAPS_PATCH + + if (center) { + if (horizontal) { + px = ax + aw / 2; + #if VANITYGAPS_PATCH + py = ay + ah / 2 + (ah - 2*ih) * (m->mfact / 2.0) + ih / 2; + #else + py = ay + ah / 2 + ah * m->mfact / 2.0; + #endif // VANITYGAPS_PATCH + } else { // vertical split + #if VANITYGAPS_PATCH + px = ax + aw / 2 + (aw - 2*iv) * m->mfact / 2.0 + iv / 2; + #else + px = ax + aw / 2 + aw * m->mfact / 2.0; + #endif // VANITYGAPS_PATCH + py = ay + ah / 2; + } + } else if (horizontal) { + px = ax + aw / 2; + if (mirror) + #if VANITYGAPS_PATCH + py = ay + (ah - ih) * (1.0 - m->mfact) + ih / 2; + #else + py = ay + (ah * (1.0 - m->mfact)); + #endif // VANITYGAPS_PATCH + else + #if VANITYGAPS_PATCH + py = ay + ((ah - ih) * m->mfact) + ih / 2; + #else + py = ay + (ah * m->mfact); + #endif // VANITYGAPS_PATCH + } else { // vertical split + if (mirror) + #if VANITYGAPS_PATCH + px = ax + (aw - iv) * (1.0 - m->mfact) + iv / 2; + #else + px = ax + (aw * m->mfact); + #endif // VANITYGAPS_PATCH + else + #if VANITYGAPS_PATCH + px = ax + ((aw - iv) * m->mfact) + iv / 2; + #else + px = ax + (aw * m->mfact); + #endif // VANITYGAPS_PATCH + py = ay + ah / 2; + } + + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, + None, cursor[horizontal ? CurResizeVertArrow : CurResizeHorzArrow]->cursor, CurrentTime) != GrabSuccess) + return; + + #if WARP_PATCH + ignore_warp = 1; + #endif // WARP_PATCH + + XWarpPointer(dpy, None, root, 0, 0, 0, 0, px, py); + + do { + XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); + switch(ev.type) { + case ConfigureRequest: + case Expose: + case MapRequest: + handler[ev.type](&ev); + break; + case MotionNotify: + if ((ev.xmotion.time - lasttime) <= (1000 / 40)) + continue; + if (lasttime != 0) { + px = ev.xmotion.x; + py = ev.xmotion.y; + } + lasttime = ev.xmotion.time; + + #if VANITYGAPS_PATCH + if (center) + if (horizontal) + if (py - ay > ah / 2) + fact = (double) 1.0 - (ay + ah - py - ih / 2) * 2 / (double) (ah - 2*ih); + else + fact = (double) 1.0 - (py - ay - ih / 2) * 2 / (double) (ah - 2*ih); + else + if (px - ax > aw / 2) + fact = (double) 1.0 - (ax + aw - px - iv / 2) * 2 / (double) (aw - 2*iv); + else + fact = (double) 1.0 - (px - ax - iv / 2) * 2 / (double) (aw - 2*iv); + else + if (horizontal) + fact = (double) (py - ay - ih / 2) / (double) (ah - ih); + else + fact = (double) (px - ax - iv / 2) / (double) (aw - iv); + #else + if (center) + if (horizontal) + if (py - ay > ah / 2) + fact = (double) 1.0 - (ay + ah - py) * 2 / (double) ah; + else + fact = (double) 1.0 - (py - ay) * 2 / (double) ah; + else + if (px - ax > aw / 2) + fact = (double) 1.0 - (ax + aw - px) * 2 / (double) aw; + else + fact = (double) 1.0 - (px - ax) * 2 / (double) aw; + else + if (horizontal) + fact = (double) (py - ay) / (double) ah; + else + fact = (double) (px - ax) / (double) aw; + #endif // VANITYGAPS_PATCH + + if (!center && mirror) + fact = 1.0 - fact; + + setmfact(&((Arg) { .f = 1.0 + fact })); + px = ev.xmotion.x; + py = ev.xmotion.y; + break; + } + } while (ev.type != ButtonRelease); + + #if WARP_PATCH + ignore_warp = 0; + #endif // WARP_PATCH + + XUngrabPointer(dpy, CurrentTime); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); +} \ No newline at end of file diff --git a/suckless/dwm/patch/dragmfact.h b/suckless/dwm/patch/dragmfact.h new file mode 100644 index 00000000..6390b717 --- /dev/null +++ b/suckless/dwm/patch/dragmfact.h @@ -0,0 +1 @@ +static void dragmfact(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/dwmc b/suckless/dwm/patch/dwmc new file mode 100755 index 00000000..66862311 --- /dev/null +++ b/suckless/dwm/patch/dwmc @@ -0,0 +1,129 @@ +#!/usr/bin/env bash + +signal() { + xsetroot -name "fsignal:$*" +} + +case $# in +1) + case $1 in + focusurgent) ;& + mirrorlayout) ;& + mpdcontrol) ;& + pushdown) ;& + pushup) ;& + self_restart) ;& + setlayout) ;& + setcfact) ;& + switchcol) ;& + view) ;& + viewall) ;& + viewtoleft) ;& + viewtoright) ;& + tagtoleft) ;& + tagtoright) ;& + tagandviewtoleft) ;& + tagandviewtoright) ;& + transfer) ;& + transferall) ;& + togglealttag) ;& + togglebar) ;& + togglefloating) ;& + togglefullscreen) ;& + fullscreen) ;& + togglefakefullscreen) ;& + togglesticky) ;& + togglehorizontalmax) ;& + toggleverticalmax) ;& + togglemax) ;& + togglegaps) ;& + defaultgaps) ;& + unfloatvisible) ;& + winview) ;& + xrdb) ;& + zoom) ;& + killclient) ;& + quit) + signal $1 + ;; + *) + echo "Unknown command ($1) or missing one argument." + exit 1 + ;; + esac + ;; +2) + case $1 in + cyclelayout) ;& + explace) ;& + moveplace) ;& + mpdchange) ;& + setkeymode) ;& + switchtag) ;& + togglescratch) ;& + view) + signal $1 ui $2 + ;; + viewex) ;& + toggleviewex) ;& + tagallmon) ;& + tagswapmon) ;& + tagex) ;& + toggletagex) ;& + setborderpx) ;& + setgaps) ;& + setlayoutex) ;& + setlayoutaxisex) ;& + swapfocus) ;& + focusstack) ;& + pushstack) ;& + inplacerotate) ;& + rotatestack) ;& + rotatelayoutaxis) ;& + incnmaster) ;& + incnstack) ;& + incrgaps) ;& + incrigaps) ;& + incrogaps) ;& + incrihgaps) ;& + incrivgaps) ;& + incrohgaps) ;& + incrovgaps) ;& + movestack) ;& + shiftview) ;& + shiftviewclients) ;& + focusmon) ;& + tagmon) + signal $1 i $2 + ;; + setcfact) ;& + setmfact) + signal $1 f $2 + ;; + *) + echo "Unknown command ($1) or too many arguments" + exit 1 + ;; + esac + ;; +5) + case $1 in + setgaps) + # Expects "setgaps oh ov ih iv" where -1 means to keep existing values + [ $2 = -1 ] && oh=128 || oh=$2 + [ $3 = -1 ] && ov=128 || ov=$3 + [ $4 = -1 ] && ih=128 || ih=$4 + [ $5 = -1 ] && iv=128 || iv=$5 + signal $1 i $(((oh << 24) + (ov << 16) + (ih << 8) + iv)) + ;; + *) + echo "Unknown command ($1) or too many arguments" + exit 1 + ;; + esac + ;; +*) + echo "Unknown command ($1) or too many arguments" + exit 1 + ;; +esac diff --git a/suckless/dwm/patch/dwmc.c b/suckless/dwm/patch/dwmc.c new file mode 100644 index 00000000..9c2e8631 --- /dev/null +++ b/suckless/dwm/patch/dwmc.c @@ -0,0 +1,100 @@ +void +setlayoutex(const Arg *arg) +{ + setlayout(&((Arg) { .v = &layouts[arg->i] })); +} + +void +viewex(const Arg *arg) +{ + view(&((Arg) { .ui = 1 << arg->ui })); +} + +void +viewallex(const Arg *arg) +{ + #if SCRATCHPADS_PATCH + view(&((Arg){.ui = ~SPTAGMASK})); + #else + view(&((Arg){.ui = ~0})); + #endif // SCRATCHPADS_PATCH +} + +void +toggleviewex(const Arg *arg) +{ + toggleview(&((Arg) { .ui = 1 << arg->ui })); +} + +void +tagex(const Arg *arg) +{ + tag(&((Arg) { .ui = 1 << arg->ui })); +} + +void +toggletagex(const Arg *arg) +{ + toggletag(&((Arg) { .ui = 1 << arg->ui })); +} + +void +tagallex(const Arg *arg) +{ + #if SCRATCHPADS_PATCH + tag(&((Arg){.ui = ~SPTAGMASK})); + #else + tag(&((Arg){.ui = ~0})); + #endif // SCRATCHPADS_PATCH +} + +int +fake_signal(void) +{ + char fsignal[256]; + char indicator[9] = "fsignal:"; + char str_sig[50]; + char param[16]; + int i, len_str_sig, n, paramn; + size_t len_fsignal, len_indicator = strlen(indicator); + Arg arg; + + // Get root name property + if (gettextprop(root, XA_WM_NAME, fsignal, sizeof(fsignal))) { + len_fsignal = strlen(fsignal); + + // Check if this is indeed a fake signal + if (len_indicator > len_fsignal ? 0 : strncmp(indicator, fsignal, len_indicator) == 0) { + paramn = sscanf(fsignal+len_indicator, "%s%n%s%n", str_sig, &len_str_sig, param, &n); + + if (paramn == 1) arg = (Arg) {0}; + else if (paramn > 2) return 1; + else if (strncmp(param, "i", n - len_str_sig) == 0) + #if IPC_PATCH + sscanf(fsignal + len_indicator + n, "%li", &(arg.i)); + #else + sscanf(fsignal + len_indicator + n, "%i", &(arg.i)); + #endif // IPC_PATCH + else if (strncmp(param, "ui", n - len_str_sig) == 0) + #if IPC_PATCH + sscanf(fsignal + len_indicator + n, "%lu", &(arg.ui)); + #else + sscanf(fsignal + len_indicator + n, "%u", &(arg.ui)); + #endif // IPC_PATCH + else if (strncmp(param, "f", n - len_str_sig) == 0) + sscanf(fsignal + len_indicator + n, "%f", &(arg.f)); + else return 1; + + // Check if a signal was found, and if so handle it + for (i = 0; i < LENGTH(signals); i++) + if (strncmp(str_sig, signals[i].sig, len_str_sig) == 0 && signals[i].func) + signals[i].func(&(arg)); + + // A fake signal was sent + return 1; + } + } + + // No fake signal was sent, so proceed with update + return 0; +} diff --git a/suckless/dwm/patch/dwmc.h b/suckless/dwm/patch/dwmc.h new file mode 100644 index 00000000..4fb04057 --- /dev/null +++ b/suckless/dwm/patch/dwmc.h @@ -0,0 +1,13 @@ +typedef struct { + const char * sig; + void (*func)(const Arg *); +} Signal; + +static void setlayoutex(const Arg *arg); +static void viewex(const Arg *arg); +static void viewallex(const Arg *arg); +static void toggleviewex(const Arg *arg); +static void tagex(const Arg *arg); +static void toggletagex(const Arg *arg); +static void tagallex(const Arg *arg); +static int fake_signal(void); diff --git a/suckless/dwm/patch/exresize.c b/suckless/dwm/patch/exresize.c new file mode 100644 index 00000000..e9786b3d --- /dev/null +++ b/suckless/dwm/patch/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 + +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, True); + 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; + #if SETBORDERPX_PATCH + int bp = selmon->borderpx; + #else + int bp = borderpx; + #endif // SETBORDERPX_PATCH + 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 = 1; + 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*bp, + 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*bp, + 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/suckless/dwm/patch/exresize.h b/suckless/dwm/patch/exresize.h new file mode 100644 index 00000000..79695ba3 --- /dev/null +++ b/suckless/dwm/patch/exresize.h @@ -0,0 +1,8 @@ +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); \ No newline at end of file diff --git a/suckless/dwm/patch/fakefullscreenclient.c b/suckless/dwm/patch/fakefullscreenclient.c new file mode 100644 index 00000000..eb51652e --- /dev/null +++ b/suckless/dwm/patch/fakefullscreenclient.c @@ -0,0 +1,18 @@ +void +togglefakefullscreen(const Arg *arg) +{ + Client *c = selmon->sel; + if (!c) + return; + + if (c->fakefullscreen != 1 && c->isfullscreen) { // exit fullscreen --> fake fullscreen + c->fakefullscreen = 2; + setfullscreen(c, 0); + } else if (c->fakefullscreen == 1) { + setfullscreen(c, 0); + c->fakefullscreen = 0; + } else { + c->fakefullscreen = 1; + setfullscreen(c, 1); + } +} diff --git a/suckless/dwm/patch/fakefullscreenclient.h b/suckless/dwm/patch/fakefullscreenclient.h new file mode 100644 index 00000000..e2a36d1a --- /dev/null +++ b/suckless/dwm/patch/fakefullscreenclient.h @@ -0,0 +1 @@ +static void togglefakefullscreen(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/floatpos.c b/suckless/dwm/patch/floatpos.c new file mode 100644 index 00000000..5d3947a3 --- /dev/null +++ b/suckless/dwm/patch/floatpos.c @@ -0,0 +1,195 @@ +void +floatpos(const Arg *arg) +{ + Client *c = selmon->sel; + + if (!c || (selmon->lt[selmon->sellt]->arrange && !c->isfloating)) + return; + + setfloatpos(c, (char *)arg->v); + resizeclient(c, c->x, c->y, c->w, c->h); + + #if !FOCUSONCLICK_PATCH + XRaiseWindow(dpy, c->win); + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2); + #endif // FOCUSONCLICK_PATCH +} + +void +setfloatpos(Client *c, const char *floatpos) +{ + char xCh, yCh, wCh, hCh; + int x, y, w, h, wx, ww, wy, wh; + #if FLOATPOS_RESPECT_GAPS_PATCH + int oh, ov, ih, iv; + unsigned int n; + #endif // FLOATPOS_RESPECT_GAPS_PATCH + + if (!c || !floatpos) + return; + if (selmon->lt[selmon->sellt]->arrange && !c->isfloating) + return; + + switch(sscanf(floatpos, "%d%c %d%c %d%c %d%c", &x, &xCh, &y, &yCh, &w, &wCh, &h, &hCh)) { + case 4: + if (xCh == 'w' || xCh == 'W') { + w = x; wCh = xCh; + h = y; hCh = yCh; + x = -1; xCh = 'C'; + y = -1; yCh = 'C'; + } else if (xCh == 'p' || xCh == 'P') { + w = x; wCh = xCh; + h = y; hCh = yCh; + x = 0; xCh = 'G'; + y = 0; yCh = 'G'; + } else if (xCh == 'm' || xCh == 'M') { + getrootptr(&x, &y); + } else { + w = 0; wCh = 0; + h = 0; hCh = 0; + } + break; + case 8: + if (xCh == 'm' || xCh == 'M') + getrootptr(&x, &y); + break; + default: + return; + } + + #if FLOATPOS_RESPECT_GAPS_PATCH + getgaps(c->mon, &oh, &ov, &ih, &iv, &n); + wx = c->mon->wx + ov; + wy = c->mon->wy + oh; + ww = c->mon->ww - 2*ov; + wh = c->mon->wh - 2*oh; + #else + wx = c->mon->wx; + wy = c->mon->wy; + ww = c->mon->ww; + wh = c->mon->wh; + #endif // FLOATPOS_RESPECT_GAPS_PATCH + + getfloatpos(x, xCh, w, wCh, wx, ww, c->x, c->w, c->bw, floatposgrid_x, &c->x, &c->w); + getfloatpos(y, yCh, h, hCh, wy, wh, c->y, c->h, c->bw, floatposgrid_y, &c->y, &c->h); +} + +/* p - position, s - size, cp and cs represents current position and size */ +void +getfloatpos(int pos, char pCh, int size, char sCh, int min_p, int max_s, int cp, int cs, int cbw, int defgrid, int *out_p, int *out_s) +{ + int abs_p, abs_s, i, delta, rest; + + abs_p = pCh == 'A' || pCh == 'a'; + abs_s = sCh == 'A' || sCh == 'a'; + + cs += 2*cbw; + + switch(pCh) { + case 'A': // absolute position + cp = pos; + break; + case 'a': // absolute relative position + cp += pos; + break; + case 'y': + case 'x': // client relative position + cp = MIN(cp + pos, min_p + max_s); + break; + case 'Y': + case 'X': // client position relative to monitor + cp = min_p + MIN(pos, max_s); + break; + case 'S': // fixed client position (sticky) + case 'C': // fixed client position (center) + case 'Z': // fixed client right-hand position (position + size) + if (pos == -1) + break; + pos = MAX(MIN(pos, max_s), 0); + if (pCh == 'Z') + cs = abs((cp + cs) - (min_p + pos)); + else if (pCh == 'C') + cs = abs((cp + cs / 2) - (min_p + pos)); + else + cs = abs(cp - (min_p + pos)); + cp = min_p + pos; + sCh = 0; // size determined by position, override defined size + break; + case 'G': // grid + if (pos <= 0) + pos = defgrid; // default configurable + if (size == 0 || pos < 2 || (sCh != 'p' && sCh != 'P')) + break; + delta = (max_s - cs) / (pos - 1); + rest = max_s - cs - delta * (pos - 1); + if (sCh == 'P') { + if (size < 1 || size > pos) + break; + cp = min_p + delta * (size - 1); + } else { + for (i = 0; i < pos && cp >= min_p + delta * i + (i > pos - rest ? i + rest - pos + 1 : 0); i++); + cp = min_p + delta * (MAX(MIN(i + size, pos), 1) - 1) + (i > pos - rest ? i + rest - pos + 1 : 0); + } + break; + } + + switch(sCh) { + case 'A': // absolute size + cs = size; + break; + case 'a': // absolute relative size + cs = MAX(1, cs + size); + break; + case '%': // client size percentage in relation to monitor window area size + if (size <= 0) + break; + size = max_s * MIN(size, 100) / 100; + /* falls through */ + case 'h': + case 'w': // size relative to client + if (sCh == 'w' || sCh == 'h') { + if (size == 0) + break; + size += cs; + } + /* falls through */ + case 'H': + case 'W': // normal size, position takes precedence + if (pCh == 'S' && cp + size > min_p + max_s) + size = min_p + max_s - cp; + else if (pCh == 'Z' && size > cp - max_s) + size = cp - min_p; + else if (size > max_s) + size = max_s; + + if (pCh == 'C') { // fixed client center, expand or contract client + delta = size - cs; + if (delta < 0 || (cp - delta / 2 + size <= min_p + max_s)) + cp -= delta / 2; + else if (cp - delta / 2 < min_p) + cp = min_p; + else if (delta) + cp = min_p + max_s; + } + + cs = size; + break; + } + + if (pCh == '%') // client mid-point position in relation to monitor window area size + cp = min_p + max_s * MAX(MIN(pos, 100), 0) / 100 - (cs) / 2; + if (pCh == 'm' || pCh == 'M') + cp = pos - cs / 2; + + if (!abs_p && cp < min_p) + cp = min_p; + if (cp + cs > min_p + max_s && !(abs_p && abs_s)) { + if (abs_p || cp == min_p) + cs = min_p + max_s - cp; + else + cp = min_p + max_s - cs; + } + + *out_p = cp; + *out_s = MAX(cs - 2*cbw, 1); +} diff --git a/suckless/dwm/patch/floatpos.h b/suckless/dwm/patch/floatpos.h new file mode 100644 index 00000000..21e94efb --- /dev/null +++ b/suckless/dwm/patch/floatpos.h @@ -0,0 +1,3 @@ +static void floatpos(const Arg *arg); +static void setfloatpos(Client *c, const char *floatpos); +static void getfloatpos(int pos, char pCh, int size, char sCh, int min_p, int max_s, int cp, int cs, int cbw, int defgrid, int *out_p, int *out_s); \ No newline at end of file diff --git a/suckless/dwm/patch/focusadjacenttag.c b/suckless/dwm/patch/focusadjacenttag.c new file mode 100644 index 00000000..5b13b542 --- /dev/null +++ b/suckless/dwm/patch/focusadjacenttag.c @@ -0,0 +1,73 @@ +void +tagtoleft(const Arg *arg) +{ + if (selmon->sel != NULL + && __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 + && selmon->tagset[selmon->seltags] > 1) { + selmon->sel->tags >>= 1; + focus(NULL); + arrange(selmon); + } +} + +void +tagtoright(const Arg *arg) +{ + if (selmon->sel != NULL + && __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 + && selmon->tagset[selmon->seltags] & (TAGMASK >> 1)) { + selmon->sel->tags <<= 1; + focus(NULL); + arrange(selmon); + } +} + +void +viewtoleft(const Arg *arg) +{ + if (__builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 + && selmon->tagset[selmon->seltags] > 1) { + selmon->seltags ^= 1; /* toggle sel tagset */ + selmon->tagset[selmon->seltags] = selmon->tagset[selmon->seltags ^ 1] >> 1; + focus(NULL); + arrange(selmon); + } +} + +void +viewtoright(const Arg *arg) +{ + if (__builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 + && selmon->tagset[selmon->seltags] & (TAGMASK >> 1)) { + selmon->seltags ^= 1; /* toggle sel tagset */ + selmon->tagset[selmon->seltags] = selmon->tagset[selmon->seltags ^ 1] << 1; + focus(NULL); + arrange(selmon); + } +} + +void +tagandviewtoleft(const Arg *arg) +{ + if (__builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 + && selmon->tagset[selmon->seltags] > 1) { + selmon->sel->tags >>= 1; + selmon->seltags ^= 1; /* toggle sel tagset */ + selmon->tagset[selmon->seltags] = selmon->tagset[selmon->seltags ^ 1] >> 1; + focus(selmon->sel); + arrange(selmon); + } +} + +void +tagandviewtoright(const Arg *arg) +{ + if (__builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 + && selmon->tagset[selmon->seltags] & (TAGMASK >> 1)) { + selmon->sel->tags <<= 1; + selmon->seltags ^= 1; /* toggle sel tagset */ + selmon->tagset[selmon->seltags] = selmon->tagset[selmon->seltags ^ 1] << 1; + focus(selmon->sel); + arrange(selmon); + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/focusadjacenttag.h b/suckless/dwm/patch/focusadjacenttag.h new file mode 100644 index 00000000..55b1019d --- /dev/null +++ b/suckless/dwm/patch/focusadjacenttag.h @@ -0,0 +1,6 @@ +static void tagtoleft(const Arg *arg); +static void tagtoright(const Arg *arg); +static void viewtoleft(const Arg *arg); +static void viewtoright(const Arg *arg); +static void tagandviewtoleft(const Arg *arg); +static void tagandviewtoright(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/focusdir.c b/suckless/dwm/patch/focusdir.c new file mode 100644 index 00000000..1807e42a --- /dev/null +++ b/suckless/dwm/patch/focusdir.c @@ -0,0 +1,65 @@ +void +focusdir(const Arg *arg) +{ + Client *s = selmon->sel, *f = NULL, *c, *next; + + if (!s) + return; + + unsigned int score = -1; + unsigned int client_score; + int dist; + int dirweight = 20; + int isfloating = s->isfloating; + + next = s->next; + if (!next) + next = s->mon->clients; + for (c = next; c != s; c = next) { + + next = c->next; + if (!next) + next = s->mon->clients; + + if (!ISVISIBLE(c) || c->isfloating != isfloating) // || HIDDEN(c) + continue; + + switch (arg->i) { + case 0: // left + dist = s->x - c->x - c->w; + client_score = + dirweight * MIN(abs(dist), abs(dist + s->mon->ww)) + + abs(s->y - c->y); + break; + case 1: // right + dist = c->x - s->x - s->w; + client_score = + dirweight * MIN(abs(dist), abs(dist + s->mon->ww)) + + abs(c->y - s->y); + break; + case 2: // up + dist = s->y - c->y - c->h; + client_score = + dirweight * MIN(abs(dist), abs(dist + s->mon->wh)) + + abs(s->x - c->x); + break; + default: + case 3: // down + dist = c->y - s->y - s->h; + client_score = + dirweight * MIN(abs(dist), abs(dist + s->mon->wh)) + + abs(c->x - s->x); + break; + } + + if (((arg->i == 0 || arg->i == 2) && client_score <= score) || client_score < score) { + score = client_score; + f = c; + } + } + + if (f && f != s) { + focus(f); + restack(f->mon); + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/focusdir.h b/suckless/dwm/patch/focusdir.h new file mode 100644 index 00000000..f0f3e5e5 --- /dev/null +++ b/suckless/dwm/patch/focusdir.h @@ -0,0 +1 @@ +static void focusdir(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/focusmaster.c b/suckless/dwm/patch/focusmaster.c new file mode 100644 index 00000000..839fb436 --- /dev/null +++ b/suckless/dwm/patch/focusmaster.c @@ -0,0 +1,13 @@ +void +focusmaster(const Arg *arg) +{ + Client *c; + + if (selmon->nmaster < 1) + return; + + c = nexttiled(selmon->clients); + + if (c) + focus(c); +} \ No newline at end of file diff --git a/suckless/dwm/patch/focusmaster.h b/suckless/dwm/patch/focusmaster.h new file mode 100644 index 00000000..5732e4b4 --- /dev/null +++ b/suckless/dwm/patch/focusmaster.h @@ -0,0 +1 @@ +static void focusmaster(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/focusurgent.c b/suckless/dwm/patch/focusurgent.c new file mode 100644 index 00000000..74946ce6 --- /dev/null +++ b/suckless/dwm/patch/focusurgent.c @@ -0,0 +1,15 @@ +void +focusurgent(const Arg *arg) +{ + Client *c; + int i; + for (c = selmon->clients; c && !c->isurgent; c = c->next); + if (c) { + for (i = 0; i < NUMTAGS && !((1 << i) & c->tags); i++); + if (i < NUMTAGS) { + if (((1 << i) & TAGMASK) != selmon->tagset[selmon->seltags]) + view(&((Arg) { .ui = 1 << i })); + focus(c); + } + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/focusurgent.h b/suckless/dwm/patch/focusurgent.h new file mode 100644 index 00000000..27ab8acb --- /dev/null +++ b/suckless/dwm/patch/focusurgent.h @@ -0,0 +1 @@ +static void focusurgent(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/fsignal.c b/suckless/dwm/patch/fsignal.c new file mode 100644 index 00000000..8ae237b7 --- /dev/null +++ b/suckless/dwm/patch/fsignal.c @@ -0,0 +1,40 @@ +int +fake_signal(void) +{ + char fsignal[256]; + char indicator[9] = "fsignal:"; + char str_signum[16]; + int i, v, signum; + size_t len_fsignal, len_indicator = strlen(indicator); + + // Get root name property + if (gettextprop(root, XA_WM_NAME, fsignal, sizeof(fsignal))) { + len_fsignal = strlen(fsignal); + + // Check if this is indeed a fake signal + if (len_indicator > len_fsignal ? 0 : strncmp(indicator, fsignal, len_indicator) == 0) { + memcpy(str_signum, &fsignal[len_indicator], len_fsignal - len_indicator); + str_signum[len_fsignal - len_indicator] = '\0'; + + // Convert string value into managable integer + for (i = signum = 0; i < strlen(str_signum); i++) { + v = str_signum[i] - '0'; + if (v >= 0 && v <= 9) { + signum = signum * 10 + v; + } + } + + // Check if a signal was found, and if so handle it + if (signum) + for (i = 0; i < LENGTH(signals); i++) + if (signum == signals[i].signum && signals[i].func) + signals[i].func(&(signals[i].arg)); + + // A fake signal was sent + return 1; + } + } + + // No fake signal was sent, so proceed with update + return 0; +} \ No newline at end of file diff --git a/suckless/dwm/patch/fsignal.h b/suckless/dwm/patch/fsignal.h new file mode 100644 index 00000000..bfb56af1 --- /dev/null +++ b/suckless/dwm/patch/fsignal.h @@ -0,0 +1,7 @@ +typedef struct { + unsigned int signum; + void (*func)(const Arg *); + const Arg arg; +} Signal; + +static int fake_signal(void); \ No newline at end of file diff --git a/suckless/dwm/patch/fullscreen.c b/suckless/dwm/patch/fullscreen.c new file mode 100644 index 00000000..a89d40db --- /dev/null +++ b/suckless/dwm/patch/fullscreen.c @@ -0,0 +1,17 @@ +Layout *last_layout; + +void +fullscreen(const Arg *arg) +{ + int monocle_pos = 0; + if (selmon->showbar || last_layout == NULL) { + #if MONOCLE_LAYOUT + for (monocle_pos = 0, last_layout = (Layout *)layouts; !last_layout->arrange || last_layout->arrange != &monocle; monocle_pos++, last_layout++ ); + #endif // MONOCLE_LAYOUT + for (last_layout = (Layout *)layouts; last_layout != selmon->lt[selmon->sellt]; last_layout++); + setlayout(&((Arg) { .v = &layouts[monocle_pos] })); + } else { + setlayout(&((Arg) { .v = last_layout })); + } + togglebar(arg); +} \ No newline at end of file diff --git a/suckless/dwm/patch/fullscreen.h b/suckless/dwm/patch/fullscreen.h new file mode 100644 index 00000000..b380c2ed --- /dev/null +++ b/suckless/dwm/patch/fullscreen.h @@ -0,0 +1 @@ +static void fullscreen(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/include.c b/suckless/dwm/patch/include.c new file mode 100644 index 00000000..7f796240 --- /dev/null +++ b/suckless/dwm/patch/include.c @@ -0,0 +1,343 @@ +/* Bar functionality */ +#include "bar_indicators.c" +#include "bar_tagicons.c" + +#if BAR_ALPHA_PATCH +#include "bar_alpha.c" +#endif +#if BAR_ALTERNATIVE_TAGS_PATCH +#include "bar_alternativetags.c" +#endif +#if BAR_ANYBAR_PATCH +#include "bar_anybar.c" +#endif +#if BAR_DWMBLOCKS_PATCH && BAR_STATUSCMD_PATCH +#include "bar_dwmblocks.c" +#endif +#if BAR_EWMHTAGS_PATCH +#include "bar_ewmhtags.c" +#endif +#if COMBO_PATCH +#include "combo.c" +#endif +#if BAR_HOLDBAR_PATCH +#include "bar_holdbar.c" +#endif +#if BAR_LTSYMBOL_PATCH +#include "bar_ltsymbol.c" +#endif +#if BAR_POWERLINE_STATUS_PATCH +#include "bar_powerline_status.c" +#endif +#if BAR_POWERLINE_TAGS_PATCH +#include "bar_powerline_tags.c" +#endif +#if BAR_STATUS_PATCH +#include "bar_status.c" +#endif +#if BAR_STATUS2D_PATCH +#include "bar_status2d.c" +#endif +#if BAR_STATUSBUTTON_PATCH +#include "bar_statusbutton.c" +#endif +#if BAR_STATUSCMD_PATCH +#include "bar_statuscmd.c" +#endif +#if BAR_STATUSCOLORS_PATCH +#include "bar_statuscolors.c" +#endif +#if BAR_TABGROUPS_PATCH +#include "bar_tabgroups.c" +#endif +#if BAR_TAGS_PATCH +#include "bar_tags.c" +#endif +#if BAR_TAGGRID_PATCH +#include "bar_taggrid.c" +#endif +#if BAR_WINTITLE_PATCH +#include "bar_wintitle.c" +#endif +#if BAR_FANCYBAR_PATCH +#include "bar_fancybar.c" +#endif +#if BAR_FLEXWINTITLE_PATCH +#include "bar_flexwintitle.c" +#if BAR_WINTITLE_FLOATING_PATCH +#include "bar_wintitle_floating.c" +#endif +#if BAR_WINTITLE_HIDDEN_PATCH +#include "bar_wintitle_hidden.c" +#endif +#endif // BAR_FLEXWINTITLE_PATCH +#if BAR_AWESOMEBAR_PATCH +#include "bar_awesomebar.c" +#endif +#if BAR_SYSTRAY_PATCH +#include "bar_systray.c" +#endif +#if BAR_VTCOLORS_PATCH +#include "bar_vtcolors.c" +#endif +#if BAR_WINTITLEACTIONS_PATCH +#include "bar_wintitleactions.c" +#endif +#if BAR_LAYOUTMENU_PATCH +#include "bar_layoutmenu.c" +#endif + +/* Other patches */ +#if ASPECTRESIZE_PATCH +#include "aspectresize.c" +#endif +#if ATTACHABOVE_PATCH || ATTACHASIDE_PATCH || ATTACHBELOW_PATCH || ATTACHBOTTOM_PATCH +#include "attachx.c" +#endif +#if AUTOSTART_PATCH +#include "autostart.c" +#endif +#if CFACTS_PATCH +#include "cfacts.c" +#endif +#if CMDCUSTOMIZE_PATCH +#include "cmdcustomize.c" +#endif +#if COOL_AUTOSTART_PATCH +#include "cool_autostart.c" +#endif +#if CYCLELAYOUTS_PATCH +#include "cyclelayouts.c" +#endif +#if DECORATION_HINTS_PATCH +#include "decorationhints.c" +#endif +#if DRAGCFACT_PATCH && CFACTS_PATCH +#include "dragcfact.c" +#endif +#if DWMC_PATCH +#include "dwmc.c" +#elif FSIGNAL_PATCH +#include "fsignal.c" +#endif +#if EXRESIZE_PATCH +#include "exresize.c" +#endif +#if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH +#include "fakefullscreenclient.c" +#endif +#if FLOATPOS_PATCH +#include "floatpos.c" +#endif +#if FOCUSADJACENTTAG_PATCH +#include "focusadjacenttag.c" +#endif +#if FOCUSDIR_PATCH +#include "focusdir.c" +#endif +#if FOCUSMASTER_PATCH +#include "focusmaster.c" +#endif +#if FOCUSURGENT_PATCH +#include "focusurgent.c" +#endif +#if FULLSCREEN_PATCH +#include "fullscreen.c" +#endif +#if INPLACEROTATE_PATCH +#include "inplacerotate.c" +#endif +#if IPC_PATCH +#include "ipc.c" +#ifdef VERSION +#include "ipc/IPCClient.c" +#include "ipc/yajl_dumps.c" +#include "ipc/ipc.c" +#include "ipc/util.c" +#endif +#endif // IPC_PATCH +#if INSETS_PATCH +#include "insets.c" +#endif +#if KEYMODES_PATCH +#include "keymodes.c" +#endif +#if KILLUNSEL_PATCH +#include "killunsel.c" +#endif +#if MAXIMIZE_PATCH +#include "maximize.c" +#endif +#if MPDCONTROL_PATCH +#include "mpdcontrol.c" +#endif +#if MOVEPLACE_PATCH +#include "moveplace.c" +#endif +#if MOVERESIZE_PATCH +#include "moveresize.c" +#endif +#if MOVESTACK_PATCH +#include "movestack.c" +#endif +#if NO_MOD_BUTTONS_PATCH +#include "nomodbuttons.c" +#endif +#if PERTAG_PATCH +#include "pertag.c" +#endif +#if PLACEMOUSE_PATCH +#include "placemouse.c" +#endif +#if PUSH_NO_MASTER_PATCH +#include "push_no_master.c" +#elif PUSH_PATCH +#include "push.c" +#endif +#if REORGANIZETAGS_PATCH +#include "reorganizetags.c" +#endif +#if RESTARTSIG_PATCH +#include "restartsig.c" +#endif +#if RIODRAW_PATCH +#include "riodraw.c" +#endif +#if ROTATESTACK_PATCH +#include "rotatestack.c" +#endif +#if ROUNDED_CORNERS_PATCH +#include "roundedcorners.c" +#endif +#if SCRATCHPADS_PATCH +#include "scratchpad.c" +#endif +#if SCRATCHPAD_ALT_1_PATCH +#include "scratchpad_alt_1.c" +#endif +#if SELFRESTART_PATCH +#include "selfrestart.c" +#endif +#if SETBORDERPX_PATCH +#include "setborderpx.c" +#endif +#if SHIFTVIEW_PATCH +#include "shiftview.c" +#endif +#if SHIFTVIEW_CLIENTS_PATCH +#include "shiftviewclients.c" +#endif +#if SIZEHINTS_RULED_PATCH +#include "sizehints_ruled.c" +#endif +#if SORTSCREENS_PATCH +#ifdef XINERAMA +#include "sortscreens.c" +#endif // XINERAMA +#endif +#if STACKER_PATCH +#include "stacker.c" +#endif +#if STICKY_PATCH +#include "sticky.c" +#endif +#if SWALLOW_PATCH +#include "swallow.c" +#endif +#if SWAPFOCUS_PATCH && PERTAG_PATCH +#include "swapfocus.c" +#endif +#if SWAPTAGS_PATCH +#include "swaptags.c" +#endif +#if SWITCHCOL_PATCH +#include "switchcol.c" +#endif +#if TAGALL_PATCH +#include "tagall.c" +#endif +#if TAGALLMON_PATCH +#include "tagallmon.c" +#endif +#if TAGOTHERMONITOR_PATCH +#include "tagothermonitor.c" +#endif +#if TAGSWAPMON_PATCH +#include "tagswapmon.c" +#endif +#if TOGGLEFULLSCREEN_PATCH +#include "togglefullscreen.c" +#endif +#if TRANSFER_PATCH +#include "transfer.c" +#endif +#if TRANSFER_ALL_PATCH +#include "transferall.c" +#endif +#if UNFLOATVISIBLE_PATCH +#include "unfloatvisible.c" +#endif +#if VANITYGAPS_PATCH +#include "vanitygaps.c" +#endif +#if WARP_PATCH +#include "warp.c" +#endif +#if WINVIEW_PATCH +#include "winview.c" +#endif +#if ZOOMSWAP_PATCH +#include "zoomswap.c" +#endif +#if XRDB_PATCH && !BAR_VTCOLORS_PATCH +#include "xrdb.c" +#endif +#if DRAGMFACT_PATCH +#include "dragmfact.c" +#endif +/* Layouts */ +#if BSTACK_LAYOUT || BSTACKHORIZ_LAYOUT || CENTEREDMASTER_LAYOUT || CENTEREDFLOATINGMASTER_LAYOUT || COLUMNS_LAYOUT || DECK_LAYOUT || TILE_LAYOUT +#include "layout_facts.c" +#endif +#if BSTACK_LAYOUT +#include "layout_bstack.c" +#endif +#if BSTACKHORIZ_LAYOUT +#include "layout_bstackhoriz.c" +#endif +#if CENTEREDMASTER_LAYOUT +#include "layout_centeredmaster.c" +#endif +#if CENTEREDFLOATINGMASTER_LAYOUT +#include "layout_centeredfloatingmaster.c" +#endif +#if COLUMNS_LAYOUT +#include "layout_columns.c" +#endif +#if DECK_LAYOUT +#include "layout_deck.c" +#endif +#if FIBONACCI_DWINDLE_LAYOUT || FIBONACCI_SPIRAL_LAYOUT +#include "layout_fibonacci.c" +#endif +#if FLEXTILE_DELUXE_LAYOUT +#include "layout_flextile-deluxe.c" +#endif +#if GAPPLESSGRID_LAYOUT +#include "layout_gapplessgrid.c" +#endif +#if GRIDMODE_LAYOUT +#include "layout_grid.c" +#endif +#if HORIZGRID_LAYOUT +#include "layout_horizgrid.c" +#endif +#if MONOCLE_LAYOUT +#include "layout_monocle.c" +#endif +#if NROWGRID_LAYOUT +#include "layout_nrowgrid.c" +#endif +#if TILE_LAYOUT +#include "layout_tile.c" +#endif diff --git a/suckless/dwm/patch/include.h b/suckless/dwm/patch/include.h new file mode 100644 index 00000000..9b3de500 --- /dev/null +++ b/suckless/dwm/patch/include.h @@ -0,0 +1,333 @@ +/* Bar functionality */ +#include "bar_indicators.h" +#include "bar_tagicons.h" + +#if BAR_ALPHA_PATCH +#include "bar_alpha.h" +#endif +#if BAR_ALTERNATIVE_TAGS_PATCH +#include "bar_alternativetags.h" +#endif +#if BAR_ANYBAR_PATCH +#include "bar_anybar.h" +#endif +#if BAR_DWMBLOCKS_PATCH && BAR_STATUSCMD_PATCH +#include "bar_dwmblocks.h" +#endif +#if BAR_EWMHTAGS_PATCH +#include "bar_ewmhtags.h" +#endif +#if COMBO_PATCH +#include "combo.h" +#endif +#if BAR_HOLDBAR_PATCH +#include "bar_holdbar.h" +#endif +#if BAR_LTSYMBOL_PATCH +#include "bar_ltsymbol.h" +#endif +#if BAR_POWERLINE_STATUS_PATCH +#include "bar_powerline_status.h" +#endif +#if BAR_POWERLINE_TAGS_PATCH +#include "bar_powerline_tags.h" +#endif +#if BAR_STATUS_PATCH +#include "bar_status.h" +#endif +#if BAR_STATUS2D_PATCH +#include "bar_status2d.h" +#endif +#if BAR_STATUSBUTTON_PATCH +#include "bar_statusbutton.h" +#endif +#if BAR_STATUSCMD_PATCH +#include "bar_statuscmd.h" +#endif +#if BAR_TABGROUPS_PATCH +#include "bar_tabgroups.h" +#endif +#if BAR_TAGS_PATCH +#include "bar_tags.h" +#endif +#if BAR_TAGGRID_PATCH +#include "bar_taggrid.h" +#endif +#if BAR_WINTITLE_PATCH +#include "bar_wintitle.h" +#endif +#if BAR_FANCYBAR_PATCH +#include "bar_fancybar.h" +#endif +#if BAR_FLEXWINTITLE_PATCH +#include "bar_flexwintitle.h" +#if BAR_WINTITLE_FLOATING_PATCH +#include "bar_wintitle_floating.h" +#endif +#if BAR_WINTITLE_HIDDEN_PATCH +#include "bar_wintitle_hidden.h" +#endif +#endif // BAR_FLEXWINTITLE_PATCH +#if BAR_AWESOMEBAR_PATCH +#include "bar_awesomebar.h" +#endif +#if BAR_SYSTRAY_PATCH +#include "bar_systray.h" +#endif +#if BAR_VTCOLORS_PATCH +#include "bar_vtcolors.h" +#endif +#if BAR_WINTITLEACTIONS_PATCH +#include "bar_wintitleactions.h" +#endif +#if BAR_LAYOUTMENU_PATCH +#include "bar_layoutmenu.h" +#endif + +/* Other patches */ +#if ASPECTRESIZE_PATCH +#include "aspectresize.h" +#endif +#if ATTACHABOVE_PATCH || ATTACHASIDE_PATCH || ATTACHBELOW_PATCH || ATTACHBOTTOM_PATCH +#include "attachx.h" +#endif +#if AUTOSTART_PATCH +#include "autostart.h" +#endif +#if CFACTS_PATCH +#include "cfacts.h" +#endif +#if CMDCUSTOMIZE_PATCH +#include "cmdcustomize.h" +#endif +#if COOL_AUTOSTART_PATCH +#include "cool_autostart.h" +#endif +#if CYCLELAYOUTS_PATCH +#include "cyclelayouts.h" +#endif +#if DECORATION_HINTS_PATCH +#include "decorationhints.h" +#endif +#if DRAGCFACT_PATCH && CFACTS_PATCH +#include "dragcfact.h" +#endif +#if DRAGMFACT_PATCH +#include "dragmfact.h" +#endif +#if DWMC_PATCH +#include "dwmc.h" +#elif FSIGNAL_PATCH +#include "fsignal.h" +#endif +#if EXRESIZE_PATCH +#include "exresize.h" +#endif +#if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH +#include "fakefullscreenclient.h" +#endif +#if FLOATPOS_PATCH +#include "floatpos.h" +#endif +#if FOCUSDIR_PATCH +#include "focusdir.h" +#endif +#if FOCUSADJACENTTAG_PATCH +#include "focusadjacenttag.h" +#endif +#if FOCUSMASTER_PATCH +#include "focusmaster.h" +#endif +#if FOCUSURGENT_PATCH +#include "focusurgent.h" +#endif +#if FULLSCREEN_PATCH +#include "fullscreen.h" +#endif +#if INPLACEROTATE_PATCH +#include "inplacerotate.h" +#endif +#if IPC_PATCH +#include "ipc.h" +#include "ipc/ipc.h" +#include "ipc/util.h" +#endif +#if INSETS_PATCH +#include "insets.h" +#endif +#if KEYMODES_PATCH +#include "keymodes.h" +#endif +#if KILLUNSEL_PATCH +#include "killunsel.h" +#endif +#if MAXIMIZE_PATCH +#include "maximize.h" +#endif +#if MPDCONTROL_PATCH +#include "mpdcontrol.h" +#endif +#if MOVEPLACE_PATCH +#include "moveplace.h" +#endif +#if MOVERESIZE_PATCH +#include "moveresize.h" +#endif +#if MOVESTACK_PATCH +#include "movestack.h" +#endif +#if NO_MOD_BUTTONS_PATCH +#include "nomodbuttons.h" +#endif +#if PERTAG_PATCH +#include "pertag.h" +#endif +#if PLACEMOUSE_PATCH +#include "placemouse.h" +#endif +#if PUSH_NO_MASTER_PATCH +#include "push_no_master.h" +#elif PUSH_PATCH +#include "push.h" +#endif +#if REORGANIZETAGS_PATCH +#include "reorganizetags.h" +#endif +#if RESTARTSIG_PATCH +#include "restartsig.h" +#endif +#if RIODRAW_PATCH +#include "riodraw.h" +#endif +#if ROTATESTACK_PATCH +#include "rotatestack.h" +#endif +#if ROUNDED_CORNERS_PATCH +#include "roundedcorners.h" +#endif +#if SCRATCHPADS_PATCH +#include "scratchpad.h" +#endif +#if SCRATCHPAD_ALT_1_PATCH +#include "scratchpad_alt_1.h" +#endif +#if SELFRESTART_PATCH +#include "selfrestart.h" +#endif +#if SETBORDERPX_PATCH +#include "setborderpx.h" +#endif +#if SHIFTVIEW_PATCH +#include "shiftview.h" +#endif +#if SHIFTVIEW_CLIENTS_PATCH +#include "shiftviewclients.h" +#endif +#if SIZEHINTS_RULED_PATCH +#include "sizehints_ruled.h" +#endif +#if SORTSCREENS_PATCH +#ifdef XINERAMA +#include "sortscreens.h" +#endif // XINERAMA +#endif +#if STACKER_PATCH +#include "stacker.h" +#endif +#if STICKY_PATCH +#include "sticky.h" +#endif +#if SWALLOW_PATCH +#include "swallow.h" +#endif +#if SWAPFOCUS_PATCH && PERTAG_PATCH +#include "swapfocus.h" +#endif +#if SWAPTAGS_PATCH +#include "swaptags.h" +#endif +#if SWITCHCOL_PATCH +#include "switchcol.h" +#endif +#if TAGALL_PATCH +#include "tagall.h" +#endif +#if TAGALLMON_PATCH +#include "tagallmon.h" +#endif +#if TAGOTHERMONITOR_PATCH +#include "tagothermonitor.h" +#endif +#if TAGSWAPMON_PATCH +#include "tagswapmon.h" +#endif +#if TOGGLEFULLSCREEN_PATCH +#include "togglefullscreen.h" +#endif +#if TRANSFER_PATCH +#include "transfer.h" +#endif +#if TRANSFER_ALL_PATCH +#include "transferall.h" +#endif +#if UNFLOATVISIBLE_PATCH +#include "unfloatvisible.h" +#endif +#if VANITYGAPS_PATCH +#include "vanitygaps.h" +#endif +#if WARP_PATCH +#include "warp.h" +#endif +#if WINVIEW_PATCH +#include "winview.h" +#endif +#if ZOOMSWAP_PATCH +#include "zoomswap.h" +#endif +#if XRDB_PATCH && !BAR_VTCOLORS_PATCH +#include "xrdb.h" +#endif +/* Layouts */ +#if BSTACK_LAYOUT +#include "layout_bstack.h" +#endif +#if BSTACKHORIZ_LAYOUT +#include "layout_bstackhoriz.h" +#endif +#if CENTEREDMASTER_LAYOUT +#include "layout_centeredmaster.h" +#endif +#if CENTEREDFLOATINGMASTER_LAYOUT +#include "layout_centeredfloatingmaster.h" +#endif +#if COLUMNS_LAYOUT +#include "layout_columns.h" +#endif +#if DECK_LAYOUT +#include "layout_deck.h" +#endif +#if FIBONACCI_DWINDLE_LAYOUT || FIBONACCI_SPIRAL_LAYOUT +#include "layout_fibonacci.h" +#endif +#if FLEXTILE_DELUXE_LAYOUT +#include "layout_flextile-deluxe.h" +#endif +#if GAPPLESSGRID_LAYOUT +#include "layout_gapplessgrid.h" +#endif +#if GRIDMODE_LAYOUT +#include "layout_grid.h" +#endif +#if HORIZGRID_LAYOUT +#include "layout_horizgrid.h" +#endif +#if MONOCLE_LAYOUT +#include "layout_monocle.h" +#endif +#if NROWGRID_LAYOUT +#include "layout_nrowgrid.h" +#endif +#if TILE_LAYOUT +#include "layout_tile.h" +#endif diff --git a/suckless/dwm/patch/inplacerotate.c b/suckless/dwm/patch/inplacerotate.c new file mode 100644 index 00000000..28eb2891 --- /dev/null +++ b/suckless/dwm/patch/inplacerotate.c @@ -0,0 +1,53 @@ +void +insertclient(Client *item, Client *insertItem, int after) +{ + Client *c; + if (item == NULL || insertItem == NULL || item == insertItem) return; + detach(insertItem); + if (!after && selmon->clients == item) { + attach(insertItem); + return; + } + if (after) { + c = item; + } else { + for (c = selmon->clients; c; c = c->next) { if (c->next == item) break; } + } + insertItem->next = c->next; + c->next = insertItem; +} + +void +inplacerotate(const Arg *arg) +{ + if (!selmon->sel || (selmon->sel->isfloating && !arg->f)) return; + + unsigned int selidx = 0, i = 0; + Client *c = NULL, *stail = NULL, *mhead = NULL, *mtail = NULL, *shead = NULL; + + // Shift client + for (c = selmon->clients; c; c = c->next) { + if (ISVISIBLE(c) && !(c->isfloating)) { + if (selmon->sel == c) { selidx = i; } + if (i == selmon->nmaster - 1) { mtail = c; } + if (i == selmon->nmaster) { shead = c; } + if (mhead == NULL) { mhead = c; } + stail = c; + i++; + } + } + if (arg->i < 0 && selidx >= selmon->nmaster) insertclient(stail, shead, 1); + if (arg->i > 0 && selidx >= selmon->nmaster) insertclient(shead, stail, 0); + if (arg->i < 0 && selidx < selmon->nmaster) insertclient(mtail, mhead, 1); + if (arg->i > 0 && selidx < selmon->nmaster) insertclient(mhead, mtail, 0); + + // Restore focus position + i = 0; + for (c = selmon->clients; c; c = c->next) { + if (!ISVISIBLE(c) || (c->isfloating)) continue; + if (i == selidx) { focus(c); break; } + i++; + } + arrange(selmon); + focus(c); +} \ No newline at end of file diff --git a/suckless/dwm/patch/inplacerotate.h b/suckless/dwm/patch/inplacerotate.h new file mode 100644 index 00000000..2767ad12 --- /dev/null +++ b/suckless/dwm/patch/inplacerotate.h @@ -0,0 +1 @@ +static void inplacerotate(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/insets.c b/suckless/dwm/patch/insets.c new file mode 100644 index 00000000..c0836cf1 --- /dev/null +++ b/suckless/dwm/patch/insets.c @@ -0,0 +1,18 @@ +void +setinset(Monitor *m, Inset inset) +{ + Bar *bar; + m->inset = inset; + updatebarpos(m); + for (bar = m->bar; bar; bar = bar->next) + XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh); + arrange(m); +} + +void +updateinset(const Arg *arg) +{ + Inset *inset = (Inset *)arg->v; + for (Monitor *m = mons; m; m = m->next) + setinset(m, *inset); +} \ No newline at end of file diff --git a/suckless/dwm/patch/insets.h b/suckless/dwm/patch/insets.h new file mode 100644 index 00000000..ab76278c --- /dev/null +++ b/suckless/dwm/patch/insets.h @@ -0,0 +1,2 @@ +static void setinset(Monitor *m, Inset inset); +static void updateinset(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/ipc.c b/suckless/dwm/patch/ipc.c new file mode 100644 index 00000000..e863afc9 --- /dev/null +++ b/suckless/dwm/patch/ipc.c @@ -0,0 +1,101 @@ +static int epoll_fd; +static int dpy_fd; +static Monitor *lastselmon; + +int +handlexevent(struct epoll_event *ev) +{ + if (ev->events & EPOLLIN) { + XEvent ev; + while (running && XPending(dpy)) { + XNextEvent(dpy, &ev); + if (handler[ev.type]) { + handler[ev.type](&ev); /* call handler */ + ipc_send_events(mons, &lastselmon, selmon); + } + } + } else if (ev-> events & EPOLLHUP) + return -1; + + return 0; +} + +void +setlayoutsafe(const Arg *arg) +{ + const Layout *ltptr = (Layout *)arg->v; + if (ltptr == 0) + setlayout(arg); + for (int i = 0; i < LENGTH(layouts); i++) { + if (ltptr == &layouts[i]) + setlayout(arg); + } +} + +void +setupepoll(void) +{ + epoll_fd = epoll_create1(0); + dpy_fd = ConnectionNumber(dpy); + struct epoll_event dpy_event; + + // Initialize struct to 0 + memset(&dpy_event, 0, sizeof(dpy_event)); + + DEBUG("Display socket is fd %d\n", dpy_fd); + + if (epoll_fd == -1) + fputs("Failed to create epoll file descriptor", stderr); + + dpy_event.events = EPOLLIN; + dpy_event.data.fd = dpy_fd; + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, dpy_fd, &dpy_event)) { + fputs("Failed to add display file descriptor to epoll", stderr); + close(epoll_fd); + exit(1); + } + + if (ipc_init(ipcsockpath, epoll_fd, ipccommands, LENGTH(ipccommands)) < 0) + fputs("Failed to initialize IPC\n", stderr); +} + +void +setstatus(const Arg *arg) +{ + Monitor *m; + #if BAR_EXTRASTATUS_PATCH + if (arg->v == NULL) { + strcpy(stext, "dwm-"VERSION); + estext[0] = '\0'; + } else { + strcpy(rawstext, arg->v); + char *e = strchr(rawstext, statussep); + if (e) { + *e = '\0'; e++; + #if BAR_STATUSCMD_PATCH + strncpy(rawestext, e, sizeof(estext) - 1); + copyvalidchars(estext, rawestext); + #else + strncpy(estext, e, sizeof(estext) - 1); + #endif // BAR_STATUSCMD_PATCH + } else { + estext[0] = '\0'; + } + #if BAR_STATUSCMD_PATCH + copyvalidchars(stext, rawstext); + #else + strncpy(stext, rawstext, sizeof(stext) - 1); + #endif // BAR_STATUSCMD_PATCH + } + #elif BAR_STATUSCMD_PATCH + if (!gettextprop(root, XA_WM_NAME, rawstext, sizeof(rawstext))) + strcpy(stext, "dwm-"VERSION); + else + copyvalidchars(stext, rawstext); + #else + if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) + strcpy(stext, "dwm-"VERSION); + #endif // BAR_EXTRASTATUS_PATCH | BAR_STATUSCMD_PATCH + for (m = mons; m; m = m->next) + drawbar(m); +} \ No newline at end of file diff --git a/suckless/dwm/patch/ipc.h b/suckless/dwm/patch/ipc.h new file mode 100644 index 00000000..a07a42f0 --- /dev/null +++ b/suckless/dwm/patch/ipc.h @@ -0,0 +1,6 @@ +#include + +static int handlexevent(struct epoll_event *ev); +static void setlayoutsafe(const Arg *arg); +static void setupepoll(void); +static void setstatus(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/ipc/IPCClient.c b/suckless/dwm/patch/ipc/IPCClient.c new file mode 100644 index 00000000..0d3eefb0 --- /dev/null +++ b/suckless/dwm/patch/ipc/IPCClient.c @@ -0,0 +1,66 @@ +#include "IPCClient.h" + +#include +#include + +#include "util.h" + +IPCClient * +ipc_client_new(int fd) +{ + IPCClient *c = (IPCClient *)malloc(sizeof(IPCClient)); + + if (c == NULL) return NULL; + + // Initialize struct + memset(&c->event, 0, sizeof(struct epoll_event)); + + c->buffer_size = 0; + c->buffer = NULL; + c->fd = fd; + c->event.data.fd = fd; + c->next = NULL; + c->prev = NULL; + c->subscriptions = 0; + + return c; +} + +void +ipc_list_add_client(IPCClientList *list, IPCClient *nc) +{ + DEBUG("Adding client with fd %d to list\n", nc->fd); + + if (*list == NULL) { + // List is empty, point list at first client + *list = nc; + } else { + IPCClient *c; + // Go to last client in list + for (c = *list; c && c->next; c = c->next) + ; + c->next = nc; + nc->prev = c; + } +} + +void +ipc_list_remove_client(IPCClientList *list, IPCClient *c) +{ + IPCClient *cprev = c->prev; + IPCClient *cnext = c->next; + + if (cprev != NULL) cprev->next = c->next; + if (cnext != NULL) cnext->prev = c->prev; + if (c == *list) *list = c->next; +} + +IPCClient * +ipc_list_get_client(IPCClientList list, int fd) +{ + for (IPCClient *c = list; c; c = c->next) { + if (c->fd == fd) return c; + } + + return NULL; +} diff --git a/suckless/dwm/patch/ipc/IPCClient.h b/suckless/dwm/patch/ipc/IPCClient.h new file mode 100644 index 00000000..307dfbad --- /dev/null +++ b/suckless/dwm/patch/ipc/IPCClient.h @@ -0,0 +1,61 @@ +#ifndef IPC_CLIENT_H_ +#define IPC_CLIENT_H_ + +#include +#include +#include + +typedef struct IPCClient IPCClient; +/** + * This structure contains the details of an IPC Client and pointers for a + * linked list + */ +struct IPCClient { + int fd; + int subscriptions; + + char *buffer; + uint32_t buffer_size; + + struct epoll_event event; + IPCClient *next; + IPCClient *prev; +}; + +typedef IPCClient *IPCClientList; + +/** + * Allocate memory for new IPCClient with the specified file descriptor and + * initialize struct. + * + * @param fd File descriptor of IPC client + * + * @return Address to allocated IPCClient struct + */ +IPCClient *ipc_client_new(int fd); + +/** + * Add an IPC Client to the specified list + * + * @param list Address of the list to add the client to + * @param nc Address of the IPCClient + */ +void ipc_list_add_client(IPCClientList *list, IPCClient *nc); + +/** + * Remove an IPCClient from the specified list + * + * @param list Address of the list to remove the client from + * @param c Address of the IPCClient + */ +void ipc_list_remove_client(IPCClientList *list, IPCClient *c); + +/** + * Get an IPCClient from the specified IPCClient list + * + * @param list List to remove the client from + * @param fd File descriptor of the IPCClient + */ +IPCClient *ipc_list_get_client(IPCClientList list, int fd); + +#endif // IPC_CLIENT_H_ diff --git a/suckless/dwm/patch/ipc/dwm-msg.c b/suckless/dwm/patch/ipc/dwm-msg.c new file mode 100644 index 00000000..089dc9f4 --- /dev/null +++ b/suckless/dwm/patch/ipc/dwm-msg.c @@ -0,0 +1,548 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IPC_MAGIC "DWM-IPC" +// clang-format off +#define IPC_MAGIC_ARR { 'D', 'W', 'M', '-', 'I', 'P', 'C' } +// clang-format on +#define IPC_MAGIC_LEN 7 // Not including null char + +#define IPC_EVENT_TAG_CHANGE "tag_change_event" +#define IPC_EVENT_CLIENT_FOCUS_CHANGE "client_focus_change_event" +#define IPC_EVENT_LAYOUT_CHANGE "layout_change_event" +#define IPC_EVENT_MONITOR_FOCUS_CHANGE "monitor_focus_change_event" +#define IPC_EVENT_FOCUSED_TITLE_CHANGE "focused_title_change_event" +#define IPC_EVENT_FOCUSED_STATE_CHANGE "focused_state_change_event" + +#define YSTR(str) yajl_gen_string(gen, (unsigned char *)str, strlen(str)) +#define YINT(num) yajl_gen_integer(gen, num) +#define YDOUBLE(num) yajl_gen_double(gen, num) +#define YBOOL(v) yajl_gen_bool(gen, v) +#define YNULL() yajl_gen_null(gen) +#define YARR(body) \ + { \ + yajl_gen_array_open(gen); \ + body; \ + yajl_gen_array_close(gen); \ + } +#define YMAP(body) \ + { \ + yajl_gen_map_open(gen); \ + body; \ + yajl_gen_map_close(gen); \ + } + +typedef unsigned long Window; + +const char *DEFAULT_SOCKET_PATH = "/tmp/dwm.sock"; +static int sock_fd = -1; +static unsigned int ignore_reply = 0; + +typedef enum IPCMessageType { + IPC_TYPE_RUN_COMMAND = 0, + IPC_TYPE_GET_MONITORS = 1, + IPC_TYPE_GET_TAGS = 2, + IPC_TYPE_GET_LAYOUTS = 3, + IPC_TYPE_GET_DWM_CLIENT = 4, + IPC_TYPE_SUBSCRIBE = 5, + IPC_TYPE_EVENT = 6 +} IPCMessageType; + +// Every IPC message must begin with this +typedef struct dwm_ipc_header { + uint8_t magic[IPC_MAGIC_LEN]; + uint32_t size; + uint8_t type; +} __attribute((packed)) dwm_ipc_header_t; + +static int +recv_message(uint8_t *msg_type, uint32_t *reply_size, uint8_t **reply) +{ + uint32_t read_bytes = 0; + const int32_t to_read = sizeof(dwm_ipc_header_t); + char header[to_read]; + char *walk = header; + + // Try to read header + while (read_bytes < to_read) { + ssize_t n = read(sock_fd, header + read_bytes, to_read - read_bytes); + + if (n == 0) { + if (read_bytes == 0) { + fprintf(stderr, "Unexpectedly reached EOF while reading header."); + fprintf(stderr, + "Read %" PRIu32 " bytes, expected %" PRIu32 " total bytes.\n", + read_bytes, to_read); + return -2; + } else { + fprintf(stderr, "Unexpectedly reached EOF while reading header."); + fprintf(stderr, + "Read %" PRIu32 " bytes, expected %" PRIu32 " total bytes.\n", + read_bytes, to_read); + return -3; + } + } else if (n == -1) { + return -1; + } + + read_bytes += n; + } + + // Check if magic string in header matches + if (memcmp(walk, IPC_MAGIC, IPC_MAGIC_LEN) != 0) { + fprintf(stderr, "Invalid magic string. Got '%.*s', expected '%s'\n", + IPC_MAGIC_LEN, walk, IPC_MAGIC); + return -3; + } + + walk += IPC_MAGIC_LEN; + + // Extract reply size + memcpy(reply_size, walk, sizeof(uint32_t)); + walk += sizeof(uint32_t); + + // Extract message type + memcpy(msg_type, walk, sizeof(uint8_t)); + walk += sizeof(uint8_t); + + (*reply) = malloc(*reply_size); + + // Extract payload + read_bytes = 0; + while (read_bytes < *reply_size) { + ssize_t n = read(sock_fd, *reply + read_bytes, *reply_size - read_bytes); + + if (n == 0) { + fprintf(stderr, "Unexpectedly reached EOF while reading payload."); + fprintf(stderr, "Read %" PRIu32 " bytes, expected %" PRIu32 " bytes.\n", + read_bytes, *reply_size); + free(*reply); + return -2; + } else if (n == -1) { + if (errno == EINTR || errno == EAGAIN) continue; + free(*reply); + return -1; + } + + read_bytes += n; + } + + return 0; +} + +static int +read_socket(IPCMessageType *msg_type, uint32_t *msg_size, char **msg) +{ + int ret = -1; + + while (ret != 0) { + ret = recv_message((uint8_t *)msg_type, msg_size, (uint8_t **)msg); + + if (ret < 0) { + // Try again (non-fatal error) + if (ret == -1 && (errno == EINTR || errno == EAGAIN)) continue; + + fprintf(stderr, "Error receiving response from socket. "); + fprintf(stderr, "The connection might have been lost.\n"); + exit(2); + } + } + + return 0; +} + +static ssize_t +write_socket(const void *buf, size_t count) +{ + size_t written = 0; + + while (written < count) { + const ssize_t n = + write(sock_fd, ((uint8_t *)buf) + written, count - written); + + if (n == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) + continue; + else + return n; + } + written += n; + } + return written; +} + +static void +connect_to_socket() +{ + struct sockaddr_un addr; + + int sock = socket(AF_UNIX, SOCK_STREAM, 0); + + // Initialize struct to 0 + memset(&addr, 0, sizeof(struct sockaddr_un)); + + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, DEFAULT_SOCKET_PATH); + + connect(sock, (const struct sockaddr *)&addr, sizeof(struct sockaddr_un)); + + sock_fd = sock; +} + +static int +send_message(IPCMessageType msg_type, uint32_t msg_size, uint8_t *msg) +{ + dwm_ipc_header_t header = { + .magic = IPC_MAGIC_ARR, .size = msg_size, .type = msg_type}; + + size_t header_size = sizeof(dwm_ipc_header_t); + size_t total_size = header_size + msg_size; + + uint8_t buffer[total_size]; + + // Copy header to buffer + memcpy(buffer, &header, header_size); + // Copy message to buffer + memcpy(buffer + header_size, msg, header.size); + + write_socket(buffer, total_size); + + return 0; +} + +static int +is_float(const char *s) +{ + size_t len = strlen(s); + int is_dot_used = 0; + int is_minus_used = 0; + + // Floats can only have one decimal point in between or digits + // Optionally, floats can also be below zero (negative) + for (int i = 0; i < len; i++) { + if (isdigit(s[i])) + continue; + else if (!is_dot_used && s[i] == '.' && i != 0 && i != len - 1) { + is_dot_used = 1; + continue; + } else if (!is_minus_used && s[i] == '-' && i == 0) { + is_minus_used = 1; + continue; + } else + return 0; + } + + return 1; +} + +static int +is_unsigned_int(const char *s) +{ + size_t len = strlen(s); + + // Unsigned int can only have digits + for (int i = 0; i < len; i++) { + if (isdigit(s[i])) + continue; + else + return 0; + } + + return 1; +} + +static int +is_signed_int(const char *s) +{ + size_t len = strlen(s); + + // Signed int can only have digits and a negative sign at the start + for (int i = 0; i < len; i++) { + if (isdigit(s[i])) + continue; + else if (i == 0 && s[i] == '-') { + continue; + } else + return 0; + } + + return 1; +} + +static void +flush_socket_reply() +{ + IPCMessageType reply_type; + uint32_t reply_size; + char *reply; + + read_socket(&reply_type, &reply_size, &reply); + + free(reply); +} + +static void +print_socket_reply() +{ + IPCMessageType reply_type; + uint32_t reply_size; + char *reply; + + read_socket(&reply_type, &reply_size, &reply); + + printf("%.*s\n", reply_size, reply); + fflush(stdout); + free(reply); +} + +static int +run_command(const char *name, char *args[], int argc) +{ + const unsigned char *msg; + size_t msg_size; + + yajl_gen gen = yajl_gen_alloc(NULL); + + // Message format: + // { + // "command": "", + // "args": [ ... ] + // } + // clang-format off + YMAP( + YSTR("command"); YSTR(name); + YSTR("args"); YARR( + for (int i = 0; i < argc; i++) { + if (is_signed_int(args[i])) { + long long num = atoll(args[i]); + YINT(num); + } else if (is_float(args[i])) { + float num = atof(args[i]); + YDOUBLE(num); + } else { + YSTR(args[i]); + } + } + ) + ) + // clang-format on + + yajl_gen_get_buf(gen, &msg, &msg_size); + + send_message(IPC_TYPE_RUN_COMMAND, msg_size, (uint8_t *)msg); + + if (!ignore_reply) + print_socket_reply(); + else + flush_socket_reply(); + + yajl_gen_free(gen); + + return 0; +} + +static int +get_monitors() +{ + send_message(IPC_TYPE_GET_MONITORS, 1, (uint8_t *)""); + print_socket_reply(); + return 0; +} + +static int +get_tags() +{ + send_message(IPC_TYPE_GET_TAGS, 1, (uint8_t *)""); + print_socket_reply(); + + return 0; +} + +static int +get_layouts() +{ + send_message(IPC_TYPE_GET_LAYOUTS, 1, (uint8_t *)""); + print_socket_reply(); + + return 0; +} + +static int +get_dwm_client(Window win) +{ + const unsigned char *msg; + size_t msg_size; + + yajl_gen gen = yajl_gen_alloc(NULL); + + // Message format: + // { + // "client_window_id": "" + // } + // clang-format off + YMAP( + YSTR("client_window_id"); YINT(win); + ) + // clang-format on + + yajl_gen_get_buf(gen, &msg, &msg_size); + + send_message(IPC_TYPE_GET_DWM_CLIENT, msg_size, (uint8_t *)msg); + + print_socket_reply(); + + yajl_gen_free(gen); + + return 0; +} + +static int +subscribe(const char *event) +{ + const unsigned char *msg; + size_t msg_size; + + yajl_gen gen = yajl_gen_alloc(NULL); + + // Message format: + // { + // "event": "", + // "action": "subscribe" + // } + // clang-format off + YMAP( + YSTR("event"); YSTR(event); + YSTR("action"); YSTR("subscribe"); + ) + // clang-format on + + yajl_gen_get_buf(gen, &msg, &msg_size); + + send_message(IPC_TYPE_SUBSCRIBE, msg_size, (uint8_t *)msg); + + if (!ignore_reply) + print_socket_reply(); + else + flush_socket_reply(); + + yajl_gen_free(gen); + + return 0; +} + +static void +usage_error(const char *prog_name, const char *format, ...) +{ + va_list args; + va_start(args, format); + + fprintf(stderr, "Error: "); + vfprintf(stderr, format, args); + fprintf(stderr, "\nusage: %s [...]\n", prog_name); + fprintf(stderr, "Try '%s help'\n", prog_name); + + va_end(args); + exit(1); +} + +static void +print_usage(const char *name) +{ + printf("usage: %s [options] [...]\n", name); + puts(""); + puts("Commands:"); + puts(" run_command [args...] Run an IPC command"); + puts(""); + puts(" get_monitors Get monitor properties"); + puts(""); + puts(" get_tags Get list of tags"); + puts(""); + puts(" get_layouts Get list of layouts"); + puts(""); + puts(" get_dwm_client Get dwm client proprties"); + puts(""); + puts(" subscribe [events...] Subscribe to specified events"); + puts(" Options: " IPC_EVENT_TAG_CHANGE ","); + puts(" " IPC_EVENT_LAYOUT_CHANGE ","); + puts(" " IPC_EVENT_CLIENT_FOCUS_CHANGE ","); + puts(" " IPC_EVENT_MONITOR_FOCUS_CHANGE ","); + puts(" " IPC_EVENT_FOCUSED_TITLE_CHANGE ","); + puts(" " IPC_EVENT_FOCUSED_STATE_CHANGE); + puts(""); + puts(" help Display this message"); + puts(""); + puts("Options:"); + puts(" --ignore-reply Don't print reply messages from"); + puts(" run_command and subscribe."); + puts(""); +} + +int +main(int argc, char *argv[]) +{ + const char *prog_name = argv[0]; + + connect_to_socket(); + if (sock_fd == -1) { + fprintf(stderr, "Failed to connect to socket\n"); + return 1; + } + + int i = 1; + if (i < argc && strcmp(argv[i], "--ignore-reply") == 0) { + ignore_reply = 1; + i++; + } + + if (i >= argc) usage_error(prog_name, "Expected an argument, got none"); + + if (!argc || strcmp(argv[i], "help") == 0) + print_usage(prog_name); + else if (strcmp(argv[i], "run_command") == 0) { + if (++i >= argc) usage_error(prog_name, "No command specified"); + // Command name + char *command = argv[i]; + // Command arguments are everything after command name + char **command_args = argv + ++i; + // Number of command arguments + int command_argc = argc - i; + run_command(command, command_args, command_argc); + } else if (strcmp(argv[i], "get_monitors") == 0) { + get_monitors(); + } else if (strcmp(argv[i], "get_tags") == 0) { + get_tags(); + } else if (strcmp(argv[i], "get_layouts") == 0) { + get_layouts(); + } else if (strcmp(argv[i], "get_dwm_client") == 0) { + if (++i < argc) { + if (is_unsigned_int(argv[i])) { + Window win = atol(argv[i]); + get_dwm_client(win); + } else + usage_error(prog_name, "Expected unsigned integer argument"); + } else + usage_error(prog_name, "Expected the window id"); + } else if (strcmp(argv[i], "subscribe") == 0) { + if (++i < argc) { + for (int j = i; j < argc; j++) subscribe(argv[j]); + } else + usage_error(prog_name, "Expected event name"); + // Keep listening for events forever + while (1) { + print_socket_reply(); + } + } else + usage_error(prog_name, "Invalid argument '%s'", argv[i]); + + return 0; +} diff --git a/suckless/dwm/patch/ipc/ipc.c b/suckless/dwm/patch/ipc/ipc.c new file mode 100644 index 00000000..0cc76a73 --- /dev/null +++ b/suckless/dwm/patch/ipc/ipc.c @@ -0,0 +1,1201 @@ +#include "ipc.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "yajl_dumps.h" + +static struct sockaddr_un sockaddr; +static struct epoll_event sock_epoll_event; +static IPCClientList ipc_clients = NULL; +static int epoll_fd = -1; +static int sock_fd = -1; +static IPCCommand *ipc_commands; +static unsigned int ipc_commands_len; +// Max size is 1 MB +static const uint32_t MAX_MESSAGE_SIZE = 1000000; +static const int IPC_SOCKET_BACKLOG = 5; + +/** + * Create IPC socket at specified path and return file descriptor to socket. + * This initializes the static variable sockaddr. + */ +static int +ipc_create_socket(const char *filename) +{ + char *normal_filename; + char *parent; + const size_t addr_size = sizeof(struct sockaddr_un); + const int sock_type = SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC; + + normalizepath(filename, &normal_filename); + + // In case socket file exists + unlink(normal_filename); + + // For portability clear the addr structure, since some implementations have + // nonstandard fields in the structure + memset(&sockaddr, 0, addr_size); + + parentdir(normal_filename, &parent); + // Create parent directories + mkdirp(parent); + free(parent); + + sockaddr.sun_family = AF_LOCAL; + strcpy(sockaddr.sun_path, normal_filename); + free(normal_filename); + + sock_fd = socket(AF_LOCAL, sock_type, 0); + if (sock_fd == -1) { + fputs("Failed to create socket\n", stderr); + return -1; + } + + DEBUG("Created socket at %s\n", sockaddr.sun_path); + + if (bind(sock_fd, (const struct sockaddr *)&sockaddr, addr_size) == -1) { + fputs("Failed to bind socket\n", stderr); + return -1; + } + + DEBUG("Socket binded\n"); + + if (listen(sock_fd, IPC_SOCKET_BACKLOG) < 0) { + fputs("Failed to listen for connections on socket\n", stderr); + return -1; + } + + DEBUG("Now listening for connections on socket\n"); + + return sock_fd; +} + +/** + * Internal function used to receive IPC messages from a given file descriptor. + * + * Returns -1 on error reading (could be EAGAIN or EINTR) + * Returns -2 if EOF before header could be read + * Returns -3 if invalid IPC header + * Returns -4 if message length exceeds MAX_MESSAGE_SIZE + */ +static int +ipc_recv_message(int fd, uint8_t *msg_type, uint32_t *reply_size, + uint8_t **reply) +{ + uint32_t read_bytes = 0; + const int32_t to_read = sizeof(dwm_ipc_header_t); + char header[to_read]; + char *walk = header; + + // Try to read header + while (read_bytes < to_read) { + const ssize_t n = read(fd, header + read_bytes, to_read - read_bytes); + + if (n == 0) { + if (read_bytes == 0) { + fprintf(stderr, "Unexpectedly reached EOF while reading header."); + fprintf(stderr, + "Read %" PRIu32 " bytes, expected %" PRIu32 " total bytes.\n", + read_bytes, to_read); + return -2; + } else { + fprintf(stderr, "Unexpectedly reached EOF while reading header."); + fprintf(stderr, + "Read %" PRIu32 " bytes, expected %" PRIu32 " total bytes.\n", + read_bytes, to_read); + return -3; + } + } else if (n == -1) { + // errno will still be set + return -1; + } + + read_bytes += n; + } + + // Check if magic string in header matches + if (memcmp(walk, IPC_MAGIC, IPC_MAGIC_LEN) != 0) { + fprintf(stderr, "Invalid magic string. Got '%.*s', expected '%s'\n", + IPC_MAGIC_LEN, walk, IPC_MAGIC); + return -3; + } + + walk += IPC_MAGIC_LEN; + + // Extract reply size + memcpy(reply_size, walk, sizeof(uint32_t)); + walk += sizeof(uint32_t); + + if (*reply_size > MAX_MESSAGE_SIZE) { + fprintf(stderr, "Message too long: %" PRIu32 " bytes. ", *reply_size); + fprintf(stderr, "Maximum message size is: %d\n", MAX_MESSAGE_SIZE); + return -4; + } + + // Extract message type + memcpy(msg_type, walk, sizeof(uint8_t)); + walk += sizeof(uint8_t); + + if (*reply_size > 0) + (*reply) = malloc(*reply_size); + else + return 0; + + read_bytes = 0; + while (read_bytes < *reply_size) { + const ssize_t n = read(fd, *reply + read_bytes, *reply_size - read_bytes); + + if (n == 0) { + fprintf(stderr, "Unexpectedly reached EOF while reading payload."); + fprintf(stderr, "Read %" PRIu32 " bytes, expected %" PRIu32 " bytes.\n", + read_bytes, *reply_size); + free(*reply); + return -2; + } else if (n == -1) { + // TODO: Should we return and wait for another epoll event? + // This would require saving the partial read in some way. + if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) continue; + + free(*reply); + return -1; + } + + read_bytes += n; + } + + return 0; +} + +/** + * Internal function used to write a buffer to a file descriptor + * + * Returns number of bytes written if successful write + * Returns 0 if no bytes were written due to EAGAIN or EWOULDBLOCK + * Returns -1 on unknown error trying to write, errno will carry over from + * write() call + */ +static ssize_t +ipc_write_message(int fd, const void *buf, size_t count) +{ + size_t written = 0; + + while (written < count) { + const ssize_t n = write(fd, (uint8_t *)buf + written, count - written); + + if (n == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + return written; + else if (errno == EINTR) + continue; + else + return n; + } + + written += n; + DEBUG("Wrote %zu/%zu to client at fd %d\n", written, count, fd); + } + + return written; +} + +/** + * Initialization for generic event message. This is used to allocate the yajl + * handle, set yajl options, and in the future any other initialization that + * should occur for event messages. + */ +static void +ipc_event_init_message(yajl_gen *gen) +{ + *gen = yajl_gen_alloc(NULL); + yajl_gen_config(*gen, yajl_gen_beautify, 1); +} + +/** + * Prepares buffers of IPC subscribers of specified event using buffer from yajl + * handle. + */ +static void +ipc_event_prepare_send_message(yajl_gen gen, IPCEvent event) +{ + const unsigned char *buffer; + size_t len = 0; + + yajl_gen_get_buf(gen, &buffer, &len); + len++; // For null char + + for (IPCClient *c = ipc_clients; c; c = c->next) { + if (c->subscriptions & event) { + DEBUG("Sending selected client change event to fd %d\n", c->fd); + ipc_prepare_send_message(c, IPC_TYPE_EVENT, len, (char *)buffer); + } + } + + // Not documented, but this frees temp_buffer + yajl_gen_free(gen); +} + +/** + * Initialization for generic reply message. This is used to allocate the yajl + * handle, set yajl options, and in the future any other initialization that + * should occur for reply messages. + */ +static void +ipc_reply_init_message(yajl_gen *gen) +{ + *gen = yajl_gen_alloc(NULL); + yajl_gen_config(*gen, yajl_gen_beautify, 1); +} + +/** + * Prepares the IPC client's buffer with a message using the buffer of the yajl + * handle. + */ +static void +ipc_reply_prepare_send_message(yajl_gen gen, IPCClient *c, + IPCMessageType msg_type) +{ + const unsigned char *buffer; + size_t len = 0; + + yajl_gen_get_buf(gen, &buffer, &len); + len++; // For null char + + ipc_prepare_send_message(c, msg_type, len, (const char *)buffer); + + // Not documented, but this frees temp_buffer + yajl_gen_free(gen); +} + +/** + * Find the IPCCommand with the specified name + * + * Returns 0 if a command with the specified name was found + * Returns -1 if a command with the specified name could not be found + */ +static int +ipc_get_ipc_command(const char *name, IPCCommand *ipc_command) +{ + for (int i = 0; i < ipc_commands_len; i++) { + if (strcmp(ipc_commands[i].name, name) == 0) { + *ipc_command = ipc_commands[i]; + return 0; + } + } + + return -1; +} + +/** + * Parse a IPC_TYPE_RUN_COMMAND message from a client. This function extracts + * the arguments, argument count, argument types, and command name and returns + * the parsed information as an IPCParsedCommand. If this function returns + * successfully, the parsed_command must be freed using + * ipc_free_parsed_command_members. + * + * Returns 0 if the message was successfully parsed + * Returns -1 otherwise + */ +static int +ipc_parse_run_command(char *msg, IPCParsedCommand *parsed_command) +{ + char error_buffer[1000]; + yajl_val parent = yajl_tree_parse(msg, error_buffer, 1000); + + if (parent == NULL) { + fputs("Failed to parse command from client\n", stderr); + fprintf(stderr, "%s\n", error_buffer); + fprintf(stderr, "Tried to parse: %s\n", msg); + return -1; + } + + // Format: + // { + // "command": "" + // "args": [ "arg1", "arg2", ... ] + // } + const char *command_path[] = {"command", 0}; + yajl_val command_val = yajl_tree_get(parent, command_path, yajl_t_string); + + if (command_val == NULL) { + fputs("No command key found in client message\n", stderr); + yajl_tree_free(parent); + return -1; + } + + const char *command_name = YAJL_GET_STRING(command_val); + size_t command_name_len = strlen(command_name); + parsed_command->name = (char *)malloc((command_name_len + 1) * sizeof(char)); + strcpy(parsed_command->name, command_name); + + DEBUG("Received command: %s\n", parsed_command->name); + + const char *args_path[] = {"args", 0}; + yajl_val args_val = yajl_tree_get(parent, args_path, yajl_t_array); + + if (args_val == NULL) { + fputs("No args key found in client message\n", stderr); + yajl_tree_free(parent); + return -1; + } + + unsigned int *argc = &parsed_command->argc; + Arg **args = &parsed_command->args; + ArgType **arg_types = &parsed_command->arg_types; + + *argc = args_val->u.array.len; + + // If no arguments are specified, make a dummy argument to pass to the + // function. This is just the way dwm's void(Arg*) functions are setup. + if (*argc == 0) { + *args = (Arg *)malloc(sizeof(Arg)); + *arg_types = (ArgType *)malloc(sizeof(ArgType)); + (*arg_types)[0] = ARG_TYPE_NONE; + (*args)[0].f = 0; + (*argc)++; + } else if (*argc > 0) { + *args = (Arg *)calloc(*argc, sizeof(Arg)); + *arg_types = (ArgType *)malloc(*argc * sizeof(ArgType)); + + for (int i = 0; i < *argc; i++) { + yajl_val arg_val = args_val->u.array.values[i]; + + if (YAJL_IS_NUMBER(arg_val)) { + if (YAJL_IS_INTEGER(arg_val)) { + // Any values below 0 must be a signed int + if (YAJL_GET_INTEGER(arg_val) < 0) { + (*args)[i].i = YAJL_GET_INTEGER(arg_val); + (*arg_types)[i] = ARG_TYPE_SINT; + DEBUG("i=%ld\n", (*args)[i].i); + // Any values above 0 should be an unsigned int + } else if (YAJL_GET_INTEGER(arg_val) >= 0) { + (*args)[i].ui = YAJL_GET_INTEGER(arg_val); + (*arg_types)[i] = ARG_TYPE_UINT; + DEBUG("ui=%ld\n", (*args)[i].i); + } + // If the number is not an integer, it must be a float + } else { + (*args)[i].f = (float)YAJL_GET_DOUBLE(arg_val); + (*arg_types)[i] = ARG_TYPE_FLOAT; + DEBUG("f=%f\n", (*args)[i].f); + // If argument is not a number, it must be a string + } + } else if (YAJL_IS_STRING(arg_val)) { + char *arg_s = YAJL_GET_STRING(arg_val); + size_t arg_s_size = (strlen(arg_s) + 1) * sizeof(char); + (*args)[i].v = (char *)malloc(arg_s_size); + (*arg_types)[i] = ARG_TYPE_STR; + strcpy((char *)(*args)[i].v, arg_s); + } + } + } + + yajl_tree_free(parent); + + return 0; +} + +/** + * Free the members of a IPCParsedCommand struct + */ +static void +ipc_free_parsed_command_members(IPCParsedCommand *command) +{ + for (int i = 0; i < command->argc; i++) { + if (command->arg_types[i] == ARG_TYPE_STR) free((void *)command->args[i].v); + } + free(command->args); + free(command->arg_types); + free(command->name); +} + +/** + * Check if the given arguments are the correct length and type. Also do any + * casting to correct the types. + * + * Returns 0 if the arguments were the correct length and types + * Returns -1 if the argument count doesn't match + * Returns -2 if the argument types don't match + */ +static int +ipc_validate_run_command(IPCParsedCommand *parsed, const IPCCommand actual) +{ + if (actual.argc != parsed->argc) return -1; + + for (int i = 0; i < parsed->argc; i++) { + ArgType ptype = parsed->arg_types[i]; + ArgType atype = actual.arg_types[i]; + + if (ptype != atype) { + if (ptype == ARG_TYPE_UINT && atype == ARG_TYPE_PTR) + // If this argument is supposed to be a void pointer, cast it + parsed->args[i].v = (void *)parsed->args[i].ui; + else if (ptype == ARG_TYPE_UINT && atype == ARG_TYPE_SINT) + // If this argument is supposed to be a signed int, cast it + parsed->args[i].i = parsed->args[i].ui; + else + return -2; + } + } + + return 0; +} + +/** + * Convert event name to their IPCEvent equivalent enum value + * + * Returns 0 if a valid event name was given + * Returns -1 otherwise + */ +static int +ipc_event_stoi(const char *subscription, IPCEvent *event) +{ + if (strcmp(subscription, "tag_change_event") == 0) + *event = IPC_EVENT_TAG_CHANGE; + else if (strcmp(subscription, "client_focus_change_event") == 0) + *event = IPC_EVENT_CLIENT_FOCUS_CHANGE; + else if (strcmp(subscription, "layout_change_event") == 0) + *event = IPC_EVENT_LAYOUT_CHANGE; + else if (strcmp(subscription, "monitor_focus_change_event") == 0) + *event = IPC_EVENT_MONITOR_FOCUS_CHANGE; + else if (strcmp(subscription, "focused_title_change_event") == 0) + *event = IPC_EVENT_FOCUSED_TITLE_CHANGE; + else if (strcmp(subscription, "focused_state_change_event") == 0) + *event = IPC_EVENT_FOCUSED_STATE_CHANGE; + else + return -1; + return 0; +} + +/** + * Parse a IPC_TYPE_SUBSCRIBE message from a client. This function extracts the + * event name and the subscription action from the message. + * + * Returns 0 if message was successfully parsed + * Returns -1 otherwise + */ +static int +ipc_parse_subscribe(const char *msg, IPCSubscriptionAction *subscribe, + IPCEvent *event) +{ + char error_buffer[100]; + yajl_val parent = yajl_tree_parse((char *)msg, error_buffer, 100); + + if (parent == NULL) { + fputs("Failed to parse command from client\n", stderr); + fprintf(stderr, "%s\n", error_buffer); + return -1; + } + + // Format: + // { + // "event": "" + // "action": "" + // } + const char *event_path[] = {"event", 0}; + yajl_val event_val = yajl_tree_get(parent, event_path, yajl_t_string); + + if (event_val == NULL) { + fputs("No 'event' key found in client message\n", stderr); + return -1; + } + + const char *event_str = YAJL_GET_STRING(event_val); + DEBUG("Received event: %s\n", event_str); + + if (ipc_event_stoi(event_str, event) < 0) return -1; + + const char *action_path[] = {"action", 0}; + yajl_val action_val = yajl_tree_get(parent, action_path, yajl_t_string); + + if (action_val == NULL) { + fputs("No 'action' key found in client message\n", stderr); + return -1; + } + + const char *action = YAJL_GET_STRING(action_val); + + if (strcmp(action, "subscribe") == 0) + *subscribe = IPC_ACTION_SUBSCRIBE; + else if (strcmp(action, "unsubscribe") == 0) + *subscribe = IPC_ACTION_UNSUBSCRIBE; + else { + fputs("Invalid action specified for subscription\n", stderr); + return -1; + } + + yajl_tree_free(parent); + + return 0; +} + +/** + * Parse an IPC_TYPE_GET_DWM_CLIENT message from a client. This function + * extracts the window id from the message. + * + * Returns 0 if message was successfully parsed + * Returns -1 otherwise + */ +static int +ipc_parse_get_dwm_client(const char *msg, Window *win) +{ + char error_buffer[100]; + + yajl_val parent = yajl_tree_parse(msg, error_buffer, 100); + + if (parent == NULL) { + fputs("Failed to parse message from client\n", stderr); + fprintf(stderr, "%s\n", error_buffer); + return -1; + } + + // Format: + // { + // "client_window_id": + // } + const char *win_path[] = {"client_window_id", 0}; + yajl_val win_val = yajl_tree_get(parent, win_path, yajl_t_number); + + if (win_val == NULL) { + fputs("No client window id found in client message\n", stderr); + return -1; + } + + *win = YAJL_GET_INTEGER(win_val); + + yajl_tree_free(parent); + + return 0; +} + +/** + * Called when an IPC_TYPE_RUN_COMMAND message is received from a client. This + * function parses, executes the given command, and prepares a reply message to + * the client indicating success/failure. + * + * NOTE: There is currently no check for argument validity beyond the number of + * arguments given and types of arguments. There is also no way to check if the + * function succeeded based on dwm's void(const Arg*) function types. Pointer + * arguments can cause crashes if they are not validated in the function itself. + * + * Returns 0 if message was successfully parsed + * Returns -1 on failure parsing message + */ +static int +ipc_run_command(IPCClient *ipc_client, char *msg) +{ + IPCParsedCommand parsed_command; + IPCCommand ipc_command; + + // Initialize struct + memset(&parsed_command, 0, sizeof(IPCParsedCommand)); + + if (ipc_parse_run_command(msg, &parsed_command) < 0) { + ipc_prepare_reply_failure(ipc_client, IPC_TYPE_RUN_COMMAND, + "Failed to parse run command"); + return -1; + } + + if (ipc_get_ipc_command(parsed_command.name, &ipc_command) < 0) { + ipc_prepare_reply_failure(ipc_client, IPC_TYPE_RUN_COMMAND, + "Command %s not found", parsed_command.name); + ipc_free_parsed_command_members(&parsed_command); + return -1; + } + + int res = ipc_validate_run_command(&parsed_command, ipc_command); + if (res < 0) { + if (res == -1) + ipc_prepare_reply_failure(ipc_client, IPC_TYPE_RUN_COMMAND, + "%u arguments provided, %u expected", + parsed_command.argc, ipc_command.argc); + else if (res == -2) + ipc_prepare_reply_failure(ipc_client, IPC_TYPE_RUN_COMMAND, + "Type mismatch"); + ipc_free_parsed_command_members(&parsed_command); + return -1; + } + + if (parsed_command.argc == 1) + ipc_command.func.single_param(parsed_command.args); + else if (parsed_command.argc > 1) + ipc_command.func.array_param(parsed_command.args, parsed_command.argc); + + DEBUG("Called function for command %s\n", parsed_command.name); + + ipc_free_parsed_command_members(&parsed_command); + + ipc_prepare_reply_success(ipc_client, IPC_TYPE_RUN_COMMAND); + return 0; +} + +/** + * Called when an IPC_TYPE_GET_MONITORS message is received from a client. It + * prepares a reply with the properties of all of the monitors in JSON. + */ +static void +ipc_get_monitors(IPCClient *c, Monitor *mons, Monitor *selmon) +{ + yajl_gen gen; + ipc_reply_init_message(&gen); + dump_monitors(gen, mons, selmon); + + ipc_reply_prepare_send_message(gen, c, IPC_TYPE_GET_MONITORS); +} + +/** + * Called when an IPC_TYPE_GET_TAGS message is received from a client. It + * prepares a reply with info about all the tags in JSON. + */ +static void +ipc_get_tags(IPCClient *c, const int tags_len) +{ + yajl_gen gen; + ipc_reply_init_message(&gen); + + dump_tags(gen, tags_len); + + ipc_reply_prepare_send_message(gen, c, IPC_TYPE_GET_TAGS); +} + +/** + * Called when an IPC_TYPE_GET_LAYOUTS message is received from a client. It + * prepares a reply with a JSON array of available layouts + */ +static void +ipc_get_layouts(IPCClient *c, const Layout layouts[], const int layouts_len) +{ + yajl_gen gen; + ipc_reply_init_message(&gen); + + dump_layouts(gen, layouts, layouts_len); + + ipc_reply_prepare_send_message(gen, c, IPC_TYPE_GET_LAYOUTS); +} + +/** + * Called when an IPC_TYPE_GET_DWM_CLIENT message is received from a client. It + * prepares a JSON reply with the properties of the client with the specified + * window XID. + * + * Returns 0 if the message was successfully parsed and if the client with the + * specified window XID was found + * Returns -1 if the message could not be parsed + */ +static int +ipc_get_dwm_client(IPCClient *ipc_client, const char *msg, const Monitor *mons) +{ + Window win; + + if (ipc_parse_get_dwm_client(msg, &win) < 0) return -1; + + // Find client with specified window XID + for (const Monitor *m = mons; m; m = m->next) + for (Client *c = m->clients; c; c = c->next) + if (c->win == win) { + yajl_gen gen; + ipc_reply_init_message(&gen); + + dump_client(gen, c); + + ipc_reply_prepare_send_message(gen, ipc_client, + IPC_TYPE_GET_DWM_CLIENT); + + return 0; + } + + ipc_prepare_reply_failure(ipc_client, IPC_TYPE_GET_DWM_CLIENT, + "Client with window id %d not found", win); + return -1; +} + +/** + * Called when an IPC_TYPE_SUBSCRIBE message is received from a client. It + * subscribes/unsubscribes the client from the specified event and replies with + * the result. + * + * Returns 0 if the message was successfully parsed. + * Returns -1 if the message could not be parsed + */ +static int +ipc_subscribe(IPCClient *c, const char *msg) +{ + IPCSubscriptionAction action = IPC_ACTION_SUBSCRIBE; + IPCEvent event = 0; + + if (ipc_parse_subscribe(msg, &action, &event)) { + ipc_prepare_reply_failure(c, IPC_TYPE_SUBSCRIBE, "Event does not exist"); + return -1; + } + + if (action == IPC_ACTION_SUBSCRIBE) { + DEBUG("Subscribing client on fd %d to %d\n", c->fd, event); + c->subscriptions |= event; + } else if (action == IPC_ACTION_UNSUBSCRIBE) { + DEBUG("Unsubscribing client on fd %d to %d\n", c->fd, event); + c->subscriptions ^= event; + } else { + ipc_prepare_reply_failure(c, IPC_TYPE_SUBSCRIBE, + "Invalid subscription action"); + return -1; + } + + ipc_prepare_reply_success(c, IPC_TYPE_SUBSCRIBE); + return 0; +} + +int +ipc_init(const char *socket_path, const int p_epoll_fd, IPCCommand commands[], + const int commands_len) +{ + // Initialize struct to 0 + memset(&sock_epoll_event, 0, sizeof(sock_epoll_event)); + + int socket_fd = ipc_create_socket(socket_path); + if (socket_fd < 0) return -1; + + ipc_commands = commands; + ipc_commands_len = commands_len; + + epoll_fd = p_epoll_fd; + + // Wake up to incoming connection requests + sock_epoll_event.data.fd = socket_fd; + sock_epoll_event.events = EPOLLIN; + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket_fd, &sock_epoll_event)) { + fputs("Failed to add sock file descriptor to epoll", stderr); + return -1; + } + + return socket_fd; +} + +void +ipc_cleanup() +{ + IPCClient *c = ipc_clients; + // Free clients and their buffers + while (c) { + ipc_drop_client(c); + c = ipc_clients; + } + + // Stop waking up for socket events + epoll_ctl(epoll_fd, EPOLL_CTL_DEL, sock_fd, &sock_epoll_event); + + // Uninitialize all static variables + epoll_fd = -1; + sock_fd = -1; + ipc_commands = NULL; + ipc_commands_len = 0; + memset(&sock_epoll_event, 0, sizeof(struct epoll_event)); + memset(&sockaddr, 0, sizeof(struct sockaddr_un)); + + // Delete socket + unlink(sockaddr.sun_path); + + shutdown(sock_fd, SHUT_RDWR); + close(sock_fd); +} + +int +ipc_get_sock_fd() +{ + return sock_fd; +} + +IPCClient * +ipc_get_client(int fd) +{ + return ipc_list_get_client(ipc_clients, fd); +} + +int +ipc_is_client_registered(int fd) +{ + return (ipc_get_client(fd) != NULL); +} + +int +ipc_accept_client() +{ + int fd = -1; + + struct sockaddr_un client_addr; + socklen_t len = 0; + + // For portability clear the addr structure, since some implementations + // have nonstandard fields in the structure + memset(&client_addr, 0, sizeof(struct sockaddr_un)); + + fd = accept(sock_fd, (struct sockaddr *)&client_addr, &len); + if (fd < 0 && errno != EINTR) { + fputs("Failed to accept IPC connection from client", stderr); + return -1; + } + + if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { + shutdown(fd, SHUT_RDWR); + close(fd); + fputs("Failed to set flags on new client fd", stderr); + } + + IPCClient *nc = ipc_client_new(fd); + if (nc == NULL) return -1; + + // Wake up to messages from this client + nc->event.data.fd = fd; + nc->event.events = EPOLLIN | EPOLLHUP; + epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &nc->event); + + ipc_list_add_client(&ipc_clients, nc); + + DEBUG("%s%d\n", "New client at fd: ", fd); + + return fd; +} + +int +ipc_drop_client(IPCClient *c) +{ + int fd = c->fd; + shutdown(fd, SHUT_RDWR); + int res = close(fd); + + if (res == 0) { + struct epoll_event ev; + + // Stop waking up to messages from this client + epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev); + ipc_list_remove_client(&ipc_clients, c); + + free(c->buffer); + free(c); + + DEBUG("Successfully removed client on fd %d\n", fd); + } else if (res < 0 && res != EINTR) { + fprintf(stderr, "Failed to close fd %d\n", fd); + } + + return res; +} + +int +ipc_read_client(IPCClient *c, IPCMessageType *msg_type, uint32_t *msg_size, + char **msg) +{ + int fd = c->fd; + int ret = + ipc_recv_message(fd, (uint8_t *)msg_type, msg_size, (uint8_t **)msg); + + if (ret < 0) { + // This will happen if these errors occur while reading header + if (ret == -1 && + (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) + return -2; + + fprintf(stderr, "Error reading message: dropping client at fd %d\n", fd); + ipc_drop_client(c); + + return -1; + } + + // Make sure receive message is null terminated to avoid parsing issues + if (*msg_size > 0) { + size_t len = *msg_size; + nullterminate(msg, &len); + *msg_size = len; + } + + DEBUG("[fd %d] ", fd); + if (*msg_size > 0) + DEBUG("Received message: '%.*s' ", *msg_size, *msg); + else + DEBUG("Received empty message "); + DEBUG("Message type: %" PRIu8 " ", (uint8_t)*msg_type); + DEBUG("Message size: %" PRIu32 "\n", *msg_size); + + return 0; +} + +ssize_t +ipc_write_client(IPCClient *c) +{ + const ssize_t n = ipc_write_message(c->fd, c->buffer, c->buffer_size); + + if (n < 0) return n; + + // TODO: Deal with client timeouts + + if (n == c->buffer_size) { + c->buffer_size = 0; + free(c->buffer); + // No dangling pointers! + c->buffer = NULL; + // Stop waking up when client is ready to receive messages + if (c->event.events & EPOLLOUT) { + c->event.events -= EPOLLOUT; + epoll_ctl(epoll_fd, EPOLL_CTL_MOD, c->fd, &c->event); + } + return n; + } + + // Shift unwritten buffer to beginning of buffer and reallocate + c->buffer_size -= n; + memmove(c->buffer, c->buffer + n, c->buffer_size); + c->buffer = (char *)realloc(c->buffer, c->buffer_size); + + return n; +} + +void +ipc_prepare_send_message(IPCClient *c, const IPCMessageType msg_type, + const uint32_t msg_size, const char *msg) +{ + dwm_ipc_header_t header = { + .magic = IPC_MAGIC_ARR, .type = msg_type, .size = msg_size}; + + uint32_t header_size = sizeof(dwm_ipc_header_t); + uint32_t packet_size = header_size + msg_size; + + if (c->buffer == NULL) + c->buffer = (char *)malloc(c->buffer_size + packet_size); + else + c->buffer = (char *)realloc(c->buffer, c->buffer_size + packet_size); + + // Copy header to end of client buffer + memcpy(c->buffer + c->buffer_size, &header, header_size); + c->buffer_size += header_size; + + // Copy message to end of client buffer + memcpy(c->buffer + c->buffer_size, msg, msg_size); + c->buffer_size += msg_size; + + // Wake up when client is ready to receive messages + c->event.events |= EPOLLOUT; + epoll_ctl(epoll_fd, EPOLL_CTL_MOD, c->fd, &c->event); +} + +void +ipc_prepare_reply_failure(IPCClient *c, IPCMessageType msg_type, + const char *format, ...) +{ + yajl_gen gen; + va_list args; + + // Get output size + va_start(args, format); + size_t len = vsnprintf(NULL, 0, format, args); + va_end(args); + char *buffer = (char *)malloc((len + 1) * sizeof(char)); + + ipc_reply_init_message(&gen); + + va_start(args, format); + vsnprintf(buffer, len + 1, format, args); + va_end(args); + dump_error_message(gen, buffer); + + ipc_reply_prepare_send_message(gen, c, msg_type); + fprintf(stderr, "[fd %d] Error: %s\n", c->fd, buffer); + + free(buffer); +} + +void +ipc_prepare_reply_success(IPCClient *c, IPCMessageType msg_type) +{ + const char *success_msg = "{\"result\":\"success\"}"; + const size_t msg_len = strlen(success_msg) + 1; // +1 for null char + + ipc_prepare_send_message(c, msg_type, msg_len, success_msg); +} + +void +ipc_tag_change_event(int mon_num, TagState old_state, TagState new_state) +{ + yajl_gen gen; + ipc_event_init_message(&gen); + dump_tag_event(gen, mon_num, old_state, new_state); + ipc_event_prepare_send_message(gen, IPC_EVENT_TAG_CHANGE); +} + +void +ipc_client_focus_change_event(int mon_num, Client *old_client, + Client *new_client) +{ + yajl_gen gen; + ipc_event_init_message(&gen); + dump_client_focus_change_event(gen, old_client, new_client, mon_num); + ipc_event_prepare_send_message(gen, IPC_EVENT_CLIENT_FOCUS_CHANGE); +} + +void +ipc_layout_change_event(const int mon_num, const char *old_symbol, + const Layout *old_layout, const char *new_symbol, + const Layout *new_layout) +{ + yajl_gen gen; + ipc_event_init_message(&gen); + dump_layout_change_event(gen, mon_num, old_symbol, old_layout, new_symbol, + new_layout); + ipc_event_prepare_send_message(gen, IPC_EVENT_LAYOUT_CHANGE); +} + +void +ipc_monitor_focus_change_event(const int last_mon_num, const int new_mon_num) +{ + yajl_gen gen; + ipc_event_init_message(&gen); + dump_monitor_focus_change_event(gen, last_mon_num, new_mon_num); + ipc_event_prepare_send_message(gen, IPC_EVENT_MONITOR_FOCUS_CHANGE); +} + +void +ipc_focused_title_change_event(const int mon_num, const Window client_id, + const char *old_name, const char *new_name) +{ + yajl_gen gen; + ipc_event_init_message(&gen); + dump_focused_title_change_event(gen, mon_num, client_id, old_name, new_name); + ipc_event_prepare_send_message(gen, IPC_EVENT_FOCUSED_TITLE_CHANGE); +} + +void +ipc_focused_state_change_event(const int mon_num, const Window client_id, + const ClientState *old_state, + const ClientState *new_state) +{ + yajl_gen gen; + ipc_event_init_message(&gen); + dump_focused_state_change_event(gen, mon_num, client_id, old_state, + new_state); + ipc_event_prepare_send_message(gen, IPC_EVENT_FOCUSED_STATE_CHANGE); +} + +void +ipc_send_events(Monitor *mons, Monitor **lastselmon, Monitor *selmon) +{ + for (Monitor *m = mons; m; m = m->next) { + unsigned int urg = 0, occ = 0, tagset = 0; + + for (Client *c = m->clients; c; c = c->next) { + occ |= c->tags; + + if (c->isurgent) urg |= c->tags; + } + tagset = m->tagset[m->seltags]; + + TagState new_state = {.selected = tagset, .occupied = occ, .urgent = urg}; + + if (memcmp(&m->tagstate, &new_state, sizeof(TagState)) != 0) { + ipc_tag_change_event(m->num, m->tagstate, new_state); + m->tagstate = new_state; + } + + if (m->lastsel != m->sel) { + ipc_client_focus_change_event(m->num, m->lastsel, m->sel); + m->lastsel = m->sel; + } + + if (strcmp(m->ltsymbol, m->lastltsymbol) != 0 || + m->lastlt != m->lt[m->sellt]) { + ipc_layout_change_event(m->num, m->lastltsymbol, m->lastlt, m->ltsymbol, + m->lt[m->sellt]); + strcpy(m->lastltsymbol, m->ltsymbol); + m->lastlt = m->lt[m->sellt]; + } + + if (*lastselmon != selmon) { + if (*lastselmon != NULL) + ipc_monitor_focus_change_event((*lastselmon)->num, selmon->num); + *lastselmon = selmon; + } + + Client *sel = m->sel; + if (!sel) continue; + ClientState *o = &m->sel->prevstate; + ClientState n = {.oldstate = sel->oldstate, + .isfixed = sel->isfixed, + .isfloating = sel->isfloating, + .isfullscreen = sel->isfullscreen, + .isurgent = sel->isurgent, + .neverfocus = sel->neverfocus}; + if (memcmp(o, &n, sizeof(ClientState)) != 0) { + ipc_focused_state_change_event(m->num, m->sel->win, o, &n); + *o = n; + } + } +} + +int +ipc_handle_client_epoll_event(struct epoll_event *ev, Monitor *mons, + Monitor **lastselmon, Monitor *selmon, const int tags_len, + const Layout *layouts, const int layouts_len) +{ + int fd = ev->data.fd; + IPCClient *c = ipc_get_client(fd); + + if (ev->events & EPOLLHUP) { + DEBUG("EPOLLHUP received from client at fd %d\n", fd); + ipc_drop_client(c); + } else if (ev->events & EPOLLOUT) { + DEBUG("Sending message to client at fd %d...\n", fd); + if (c->buffer_size) ipc_write_client(c); + } else if (ev->events & EPOLLIN) { + IPCMessageType msg_type = 0; + uint32_t msg_size = 0; + char *msg = NULL; + + DEBUG("Received message from fd %d\n", fd); + if (ipc_read_client(c, &msg_type, &msg_size, &msg) < 0) return -1; + + if (msg_type == IPC_TYPE_GET_MONITORS) + ipc_get_monitors(c, mons, selmon); + else if (msg_type == IPC_TYPE_GET_TAGS) + ipc_get_tags(c, tags_len); + else if (msg_type == IPC_TYPE_GET_LAYOUTS) + ipc_get_layouts(c, layouts, layouts_len); + else if (msg_type == IPC_TYPE_RUN_COMMAND) { + if (ipc_run_command(c, msg) < 0) return -1; + ipc_send_events(mons, lastselmon, selmon); + } else if (msg_type == IPC_TYPE_GET_DWM_CLIENT) { + if (ipc_get_dwm_client(c, msg, mons) < 0) return -1; + } else if (msg_type == IPC_TYPE_SUBSCRIBE) { + if (ipc_subscribe(c, msg) < 0) return -1; + } else { + fprintf(stderr, "Invalid message type received from fd %d", fd); + ipc_prepare_reply_failure(c, msg_type, "Invalid message type: %d", + msg_type); + } + free(msg); + } else { + fprintf(stderr, "Epoll event returned %d from fd %d\n", ev->events, fd); + return -1; + } + + return 0; +} + +int +ipc_handle_socket_epoll_event(struct epoll_event *ev) +{ + if (!(ev->events & EPOLLIN)) return -1; + + // EPOLLIN means incoming client connection request + fputs("Received EPOLLIN event on socket\n", stderr); + int new_fd = ipc_accept_client(); + + return new_fd; +} diff --git a/suckless/dwm/patch/ipc/ipc.h b/suckless/dwm/patch/ipc/ipc.h new file mode 100644 index 00000000..29ec036a --- /dev/null +++ b/suckless/dwm/patch/ipc/ipc.h @@ -0,0 +1,319 @@ +#ifndef IPC_H_ +#define IPC_H_ + +#include +#include +#include + +#include "IPCClient.h" + +// clang-format off +#define IPC_MAGIC "DWM-IPC" +#define IPC_MAGIC_ARR { 'D', 'W', 'M', '-', 'I', 'P', 'C'} +#define IPC_MAGIC_LEN 7 // Not including null char + +#define IPCCOMMAND(FUNC, ARGC, TYPES) \ + { #FUNC, {FUNC }, ARGC, (ArgType[ARGC])TYPES } +// clang-format on + +typedef enum IPCMessageType { + IPC_TYPE_RUN_COMMAND = 0, + IPC_TYPE_GET_MONITORS = 1, + IPC_TYPE_GET_TAGS = 2, + IPC_TYPE_GET_LAYOUTS = 3, + IPC_TYPE_GET_DWM_CLIENT = 4, + IPC_TYPE_SUBSCRIBE = 5, + IPC_TYPE_EVENT = 6 +} IPCMessageType; + +typedef enum IPCEvent { + IPC_EVENT_TAG_CHANGE = 1 << 0, + IPC_EVENT_CLIENT_FOCUS_CHANGE = 1 << 1, + IPC_EVENT_LAYOUT_CHANGE = 1 << 2, + IPC_EVENT_MONITOR_FOCUS_CHANGE = 1 << 3, + IPC_EVENT_FOCUSED_TITLE_CHANGE = 1 << 4, + IPC_EVENT_FOCUSED_STATE_CHANGE = 1 << 5 +} IPCEvent; + +typedef enum IPCSubscriptionAction { + IPC_ACTION_UNSUBSCRIBE = 0, + IPC_ACTION_SUBSCRIBE = 1 +} IPCSubscriptionAction; + +/** + * Every IPC packet starts with this structure + */ +typedef struct dwm_ipc_header { + uint8_t magic[IPC_MAGIC_LEN]; + uint32_t size; + uint8_t type; +} __attribute((packed)) dwm_ipc_header_t; + +typedef enum ArgType { + ARG_TYPE_NONE = 0, + ARG_TYPE_UINT = 1, + ARG_TYPE_SINT = 2, + ARG_TYPE_FLOAT = 3, + ARG_TYPE_PTR = 4, + ARG_TYPE_STR = 5 +} ArgType; + +/** + * An IPCCommand function can have either of these function signatures + */ +typedef union ArgFunction { + void (*single_param)(const Arg *); + void (*array_param)(const Arg *, int); +} ArgFunction; + +typedef struct IPCCommand { + char *name; + ArgFunction func; + unsigned int argc; + ArgType *arg_types; +} IPCCommand; + +typedef struct IPCParsedCommand { + char *name; + Arg *args; + ArgType *arg_types; + unsigned int argc; +} IPCParsedCommand; + +/** + * Initialize the IPC socket and the IPC module + * + * @param socket_path Path to create the socket at + * @param epoll_fd File descriptor for epoll + * @param commands Address of IPCCommands array defined in config.h + * @param commands_len Length of commands[] array + * + * @return int The file descriptor of the socket if it was successfully created, + * -1 otherwise + */ +int ipc_init(const char *socket_path, const int p_epoll_fd, + IPCCommand commands[], const int commands_len); + +/** + * Uninitialize the socket and module. Free allocated memory and restore static + * variables to their state before ipc_init + */ +void ipc_cleanup(); + +/** + * Get the file descriptor of the IPC socket + * + * @return int File descriptor of IPC socket, -1 if socket not created. + */ +int ipc_get_sock_fd(); + +/** + * Get address to IPCClient with specified file descriptor + * + * @param fd File descriptor of IPC Client + * + * @return Address to IPCClient with specified file descriptor, -1 otherwise + */ +IPCClient *ipc_get_client(int fd); + +/** + * Check if an IPC client exists with the specified file descriptor + * + * @param fd File descriptor + * + * @return int 1 if client exists, 0 otherwise + */ +int ipc_is_client_registered(int fd); + +/** + * Disconnect an IPCClient from the socket and remove the client from the list + * of known connected clients + * + * @param c Address of IPCClient + * + * @return 0 if the client's file descriptor was closed successfully, the + * result of executing close() on the file descriptor otherwise. + */ +int ipc_drop_client(IPCClient *c); + +/** + * Accept an IPC Client requesting to connect to the socket and add it to the + * list of clients + * + * @return File descriptor of new client, -1 on error + */ +int ipc_accept_client(); + +/** + * Read an incoming message from an accepted IPC client + * + * @param c Address of IPCClient + * @param msg_type Address to IPCMessageType variable which will be assigned + * the message type of the received message + * @param msg_size Address to uint32_t variable which will be assigned the size + * of the received message + * @param msg Address to char* variable which will be assigned the address of + * the received message. This must be freed using free(). + * + * @return 0 on success, -1 on error reading message, -2 if reading the message + * resulted in EAGAIN, EINTR, or EWOULDBLOCK. + */ +int ipc_read_client(IPCClient *c, IPCMessageType *msg_type, uint32_t *msg_size, + char **msg); + +/** + * Write any pending buffer of the client to the client's socket + * + * @param c Client whose buffer to write + * + * @return Number of bytes written >= 0, -1 otherwise. errno will still be set + * from the write operation. + */ +ssize_t ipc_write_client(IPCClient *c); + +/** + * Prepare a message in the specified client's buffer. + * + * @param c Client to prepare message for + * @param msg_type Type of message to prepare + * @param msg_size Size of the message in bytes. Should not exceed + * MAX_MESSAGE_SIZE + * @param msg Message to prepare (not including header). This pointer can be + * freed after the function invocation. + */ +void ipc_prepare_send_message(IPCClient *c, const IPCMessageType msg_type, + const uint32_t msg_size, const char *msg); + +/** + * Prepare an error message in the specified client's buffer + * + * @param c Client to prepare message for + * @param msg_type Type of message + * @param format Format string following vsprintf + * @param ... Arguments for format string + */ +void ipc_prepare_reply_failure(IPCClient *c, IPCMessageType msg_type, + const char *format, ...); + +/** + * Prepare a success message in the specified client's buffer + * + * @param c Client to prepare message for + * @param msg_type Type of message + */ +void ipc_prepare_reply_success(IPCClient *c, IPCMessageType msg_type); + +/** + * Send a tag_change_event to all subscribers. Should be called only when there + * has been a tag state change. + * + * @param mon_num The index of the monitor (Monitor.num property) + * @param old_state The old tag state + * @param new_state The new (now current) tag state + */ +void ipc_tag_change_event(const int mon_num, TagState old_state, + TagState new_state); + +/** + * Send a client_focus_change_event to all subscribers. Should be called only + * when the client focus changes. + * + * @param mon_num The index of the monitor (Monitor.num property) + * @param old_client The old DWM client selection (Monitor.oldsel) + * @param new_client The new (now current) DWM client selection + */ +void ipc_client_focus_change_event(const int mon_num, Client *old_client, + Client *new_client); + +/** + * Send a layout_change_event to all subscribers. Should be called only + * when there has been a layout change. + * + * @param mon_num The index of the monitor (Monitor.num property) + * @param old_symbol The old layout symbol + * @param old_layout Address to the old Layout + * @param new_symbol The new (now current) layout symbol + * @param new_layout Address to the new Layout + */ +void ipc_layout_change_event(const int mon_num, const char *old_symbol, + const Layout *old_layout, const char *new_symbol, + const Layout *new_layout); + +/** + * Send a monitor_focus_change_event to all subscribers. Should be called only + * when the monitor focus changes. + * + * @param last_mon_num The index of the previously selected monitor + * @param new_mon_num The index of the newly selected monitor + */ +void ipc_monitor_focus_change_event(const int last_mon_num, + const int new_mon_num); + +/** + * Send a focused_title_change_event to all subscribers. Should only be called + * if a selected client has a title change. + * + * @param mon_num Index of the client's monitor + * @param client_id Window XID of client + * @param old_name Old name of the client window + * @param new_name New name of the client window + */ +void ipc_focused_title_change_event(const int mon_num, const Window client_id, + const char *old_name, const char *new_name); + +/** + * Send a focused_state_change_event to all subscribers. Should only be called + * if a selected client has a state change. + * + * @param mon_num Index of the client's monitor + * @param client_id Window XID of client + * @param old_state Old state of the client + * @param new_state New state of the client + */ +void ipc_focused_state_change_event(const int mon_num, const Window client_id, + const ClientState *old_state, + const ClientState *new_state); +/** + * Check to see if an event has occured and call the *_change_event functions + * accordingly + * + * @param mons Address of Monitor pointing to start of linked list + * @param lastselmon Address of pointer to previously selected monitor + * @param selmon Address of selected Monitor + */ +void ipc_send_events(Monitor *mons, Monitor **lastselmon, Monitor *selmon); + +/** + * Handle an epoll event caused by a registered IPC client. Read, process, and + * handle any received messages from clients. Write pending buffer to client if + * the client is ready to receive messages. Drop clients that have sent an + * EPOLLHUP. + * + * @param ev Associated epoll event returned by epoll_wait + * @param mons Address of Monitor pointing to start of linked list + * @param selmon Address of selected Monitor + * @param lastselmon Address of pointer to previously selected monitor + * @param tags Array of tag names + * @param tags_len Length of tags array + * @param layouts Array of available layouts + * @param layouts_len Length of layouts array + * + * @return 0 if event was successfully handled, -1 on any error receiving + * or handling incoming messages or unhandled epoll event. + */ +int ipc_handle_client_epoll_event(struct epoll_event *ev, Monitor *mons, + Monitor **lastselmon, Monitor *selmon, const int tags_len, + const Layout *layouts, const int layouts_len); + +/** + * Handle an epoll event caused by the IPC socket. This function only handles an + * EPOLLIN event indicating a new client requesting to connect to the socket. + * + * @param ev Associated epoll event returned by epoll_wait + * + * @return 0, if the event was successfully handled, -1 if not an EPOLLIN event + * or if a new IPC client connection request could not be accepted. + */ +int ipc_handle_socket_epoll_event(struct epoll_event *ev); + +#endif /* IPC_H_ */ diff --git a/suckless/dwm/patch/ipc/util.c b/suckless/dwm/patch/ipc/util.c new file mode 100644 index 00000000..fedfc93c --- /dev/null +++ b/suckless/dwm/patch/ipc/util.c @@ -0,0 +1,135 @@ +#include +#include + +int +normalizepath(const char *path, char **normal) +{ + size_t len = strlen(path); + *normal = (char *)malloc((len + 1) * sizeof(char)); + const char *walk = path; + const char *match; + size_t newlen = 0; + + while ((match = strchr(walk, '/'))) { + // Copy everything between match and walk + strncpy(*normal + newlen, walk, match - walk); + newlen += match - walk; + walk += match - walk; + + // Skip all repeating slashes + while (*walk == '/') + walk++; + + // If not last character in path + if (walk != path + len) + (*normal)[newlen++] = '/'; + } + + (*normal)[newlen++] = '\0'; + + // Copy remaining path + strcat(*normal, walk); + newlen += strlen(walk); + + *normal = (char *)realloc(*normal, newlen * sizeof(char)); + + return 0; +} + +int +parentdir(const char *path, char **parent) +{ + char *normal; + char *walk; + + normalizepath(path, &normal); + + // Pointer to last '/' + if (!(walk = strrchr(normal, '/'))) { + free(normal); + return -1; + } + + // Get path up to last '/' + size_t len = walk - normal; + *parent = (char *)malloc((len + 1) * sizeof(char)); + + // Copy path up to last '/' + strncpy(*parent, normal, len); + // Add null char + (*parent)[len] = '\0'; + + free(normal); + + return 0; +} + +int +mkdirp(const char *path) +{ + char *normal; + char *walk; + size_t normallen; + + normalizepath(path, &normal); + normallen = strlen(normal); + walk = normal; + + while (walk < normal + normallen + 1) { + // Get length from walk to next / + size_t n = strcspn(walk, "/"); + + // Skip path / + if (n == 0) { + walk++; + continue; + } + + // Length of current path segment + size_t curpathlen = walk - normal + n; + char curpath[curpathlen + 1]; + struct stat s; + + // Copy path segment to stat + strncpy(curpath, normal, curpathlen); + strcpy(curpath + curpathlen, ""); + int res = stat(curpath, &s); + + if (res < 0) { + if (errno == ENOENT) { + DEBUG("Making directory %s\n", curpath); + if (mkdir(curpath, 0700) < 0) { + fprintf(stderr, "Failed to make directory %s\n", curpath); + perror(""); + free(normal); + return -1; + } + } else { + fprintf(stderr, "Error statting directory %s\n", curpath); + perror(""); + free(normal); + return -1; + } + } + + // Continue to next path segment + walk += n; + } + + free(normal); + + return 0; +} + +int +nullterminate(char **str, size_t *len) +{ + if ((*str)[*len - 1] == '\0') + return 0; + + (*len)++; + *str = (char*)realloc(*str, *len * sizeof(char)); + (*str)[*len - 1] = '\0'; + + return 0; +} diff --git a/suckless/dwm/patch/ipc/util.h b/suckless/dwm/patch/ipc/util.h new file mode 100644 index 00000000..8f8d35fd --- /dev/null +++ b/suckless/dwm/patch/ipc/util.h @@ -0,0 +1,4 @@ +int normalizepath(const char *path, char **normal); +int mkdirp(const char *path); +int parentdir(const char *path, char **parent); +int nullterminate(char **str, size_t *len); \ No newline at end of file diff --git a/suckless/dwm/patch/ipc/yajl_dumps.c b/suckless/dwm/patch/ipc/yajl_dumps.c new file mode 100644 index 00000000..d5d2a61d --- /dev/null +++ b/suckless/dwm/patch/ipc/yajl_dumps.c @@ -0,0 +1,351 @@ +#include "yajl_dumps.h" + +#include + +int +dump_tag(yajl_gen gen, const char *name, const int tag_mask) +{ + // clang-format off + YMAP( + YSTR("bit_mask"); YINT(tag_mask); + YSTR("name"); YSTR(name); + ) + // clang-format on + + return 0; +} + +int +dump_tags(yajl_gen gen, int tags_len) +{ + // clang-format off + YARR( + for (int i = 0; i < tags_len; i++) + dump_tag(gen, tagicon(mons, i), 1 << i); + ) + // clang-format on + + return 0; +} + +int +dump_client(yajl_gen gen, Client *c) +{ + // clang-format off + YMAP( + YSTR("name"); YSTR(c->name); + YSTR("tags"); YINT(c->tags); + YSTR("window_id"); YINT(c->win); + YSTR("monitor_number"); YINT(c->mon->num); + + YSTR("geometry"); YMAP( + YSTR("current"); YMAP ( + YSTR("x"); YINT(c->x); + YSTR("y"); YINT(c->y); + YSTR("width"); YINT(c->w); + YSTR("height"); YINT(c->h); + ) + YSTR("old"); YMAP( + YSTR("x"); YINT(c->oldx); + YSTR("y"); YINT(c->oldy); + YSTR("width"); YINT(c->oldw); + YSTR("height"); YINT(c->oldh); + ) + ) + + YSTR("size_hints"); YMAP( + YSTR("base"); YMAP( + YSTR("width"); YINT(c->basew); + YSTR("height"); YINT(c->baseh); + ) + YSTR("step"); YMAP( + YSTR("width"); YINT(c->incw); + YSTR("height"); YINT(c->inch); + ) + YSTR("max"); YMAP( + YSTR("width"); YINT(c->maxw); + YSTR("height"); YINT(c->maxh); + ) + YSTR("min"); YMAP( + YSTR("width"); YINT(c->minw); + YSTR("height"); YINT(c->minh); + ) + YSTR("aspect_ratio"); YMAP( + YSTR("min"); YDOUBLE(c->mina); + YSTR("max"); YDOUBLE(c->maxa); + ) + ) + + YSTR("border_width"); YMAP( + YSTR("current"); YINT(c->bw); + YSTR("old"); YINT(c->oldbw); + ) + + YSTR("states"); YMAP( + YSTR("is_fixed"); YBOOL(c->isfixed); + YSTR("is_floating"); YBOOL(c->isfloating); + YSTR("is_urgent"); YBOOL(c->isurgent); + YSTR("never_focus"); YBOOL(c->neverfocus); + YSTR("old_state"); YBOOL(c->oldstate); + YSTR("is_fullscreen"); YBOOL(c->isfullscreen); + ) + ) + // clang-format on + + return 0; +} + +int +dump_monitor(yajl_gen gen, Monitor *mon, int is_selected) +{ + // clang-format off + YMAP( + YSTR("master_factor"); YDOUBLE(mon->mfact); + YSTR("num_master"); YINT(mon->nmaster); + YSTR("num"); YINT(mon->num); + YSTR("is_selected"); YBOOL(is_selected); + + YSTR("monitor_geometry"); YMAP( + YSTR("x"); YINT(mon->mx); + YSTR("y"); YINT(mon->my); + YSTR("width"); YINT(mon->mw); + YSTR("height"); YINT(mon->mh); + ) + + YSTR("window_geometry"); YMAP( + YSTR("x"); YINT(mon->wx); + YSTR("y"); YINT(mon->wy); + YSTR("width"); YINT(mon->ww); + YSTR("height"); YINT(mon->wh); + ) + + YSTR("tagset"); YMAP( + YSTR("current"); YINT(mon->tagset[mon->seltags]); + YSTR("old"); YINT(mon->tagset[mon->seltags ^ 1]); + ) + + YSTR("tag_state"); dump_tag_state(gen, mon->tagstate); + + YSTR("clients"); YMAP( + YSTR("selected"); YINT(mon->sel ? mon->sel->win : 0); + YSTR("stack"); YARR( + for (Client* c = mon->stack; c; c = c->snext) + YINT(c->win); + ) + YSTR("all"); YARR( + for (Client* c = mon->clients; c; c = c->next) + YINT(c->win); + ) + ) + + YSTR("layout"); YMAP( + YSTR("symbol"); YMAP( + YSTR("current"); YSTR(mon->ltsymbol); + YSTR("old"); YSTR(mon->lastltsymbol); + ) + YSTR("address"); YMAP( + YSTR("current"); YINT((uintptr_t)mon->lt[mon->sellt]); + YSTR("old"); YINT((uintptr_t)mon->lt[mon->sellt ^ 1]); + ) + ) + + YSTR("bar"); YMAP( + YSTR("y"); YINT(mon->bar->by); + YSTR("is_shown"); YBOOL(mon->showbar); + YSTR("is_top"); YBOOL(mon->bar->topbar); + YSTR("window_id"); YINT(mon->bar->win); + ) + ) + // clang-format on + + return 0; +} + +int +dump_monitors(yajl_gen gen, Monitor *mons, Monitor *selmon) +{ + // clang-format off + YARR( + for (Monitor *mon = mons; mon; mon = mon->next) { + if (mon == selmon) + dump_monitor(gen, mon, 1); + else + dump_monitor(gen, mon, 0); + } + ) + // clang-format on + + return 0; +} + +int +dump_layouts(yajl_gen gen, const Layout layouts[], const int layouts_len) +{ + // clang-format off + YARR( + for (int i = 0; i < layouts_len; i++) { + YMAP( + // Check for a NULL pointer. The cycle layouts patch adds an entry at + // the end of the layouts array with a NULL pointer for the symbol + YSTR("symbol"); YSTR((layouts[i].symbol ? layouts[i].symbol : "")); + YSTR("address"); YINT((uintptr_t)(layouts + i)); + ) + } + ) + // clang-format on + + return 0; +} + +int +dump_tag_state(yajl_gen gen, TagState state) +{ + // clang-format off + YMAP( + YSTR("selected"); YINT(state.selected); + YSTR("occupied"); YINT(state.occupied); + YSTR("urgent"); YINT(state.urgent); + ) + // clang-format on + + return 0; +} + +int +dump_tag_event(yajl_gen gen, int mon_num, TagState old_state, + TagState new_state) +{ + // clang-format off + YMAP( + YSTR("tag_change_event"); YMAP( + YSTR("monitor_number"); YINT(mon_num); + YSTR("old_state"); dump_tag_state(gen, old_state); + YSTR("new_state"); dump_tag_state(gen, new_state); + ) + ) + // clang-format on + + return 0; +} + +int +dump_client_focus_change_event(yajl_gen gen, Client *old_client, + Client *new_client, int mon_num) +{ + // clang-format off + YMAP( + YSTR("client_focus_change_event"); YMAP( + YSTR("monitor_number"); YINT(mon_num); + YSTR("old_win_id"); old_client == NULL ? YNULL() : YINT(old_client->win); + YSTR("new_win_id"); new_client == NULL ? YNULL() : YINT(new_client->win); + ) + ) + // clang-format on + + return 0; +} + +int +dump_layout_change_event(yajl_gen gen, const int mon_num, + const char *old_symbol, const Layout *old_layout, + const char *new_symbol, const Layout *new_layout) +{ + // clang-format off + YMAP( + YSTR("layout_change_event"); YMAP( + YSTR("monitor_number"); YINT(mon_num); + YSTR("old_symbol"); YSTR(old_symbol); + YSTR("old_address"); YINT((uintptr_t)old_layout); + YSTR("new_symbol"); YSTR(new_symbol); + YSTR("new_address"); YINT((uintptr_t)new_layout); + ) + ) + // clang-format on + + return 0; +} + +int +dump_monitor_focus_change_event(yajl_gen gen, const int last_mon_num, + const int new_mon_num) +{ + // clang-format off + YMAP( + YSTR("monitor_focus_change_event"); YMAP( + YSTR("old_monitor_number"); YINT(last_mon_num); + YSTR("new_monitor_number"); YINT(new_mon_num); + ) + ) + // clang-format on + + return 0; +} + +int +dump_focused_title_change_event(yajl_gen gen, const int mon_num, + const Window client_id, const char *old_name, + const char *new_name) +{ + // clang-format off + YMAP( + YSTR("focused_title_change_event"); YMAP( + YSTR("monitor_number"); YINT(mon_num); + YSTR("client_window_id"); YINT(client_id); + YSTR("old_name"); YSTR(old_name); + YSTR("new_name"); YSTR(new_name); + ) + ) + // clang-format on + + return 0; +} + +int +dump_client_state(yajl_gen gen, const ClientState *state) +{ + // clang-format off + YMAP( + YSTR("old_state"); YBOOL(state->oldstate); + YSTR("is_fixed"); YBOOL(state->isfixed); + YSTR("is_floating"); YBOOL(state->isfloating); + YSTR("is_fullscreen"); YBOOL(state->isfullscreen); + YSTR("is_urgent"); YBOOL(state->isurgent); + YSTR("never_focus"); YBOOL(state->neverfocus); + ) + // clang-format on + + return 0; +} + +int +dump_focused_state_change_event(yajl_gen gen, const int mon_num, + const Window client_id, + const ClientState *old_state, + const ClientState *new_state) +{ + // clang-format off + YMAP( + YSTR("focused_state_change_event"); YMAP( + YSTR("monitor_number"); YINT(mon_num); + YSTR("client_window_id"); YINT(client_id); + YSTR("old_state"); dump_client_state(gen, old_state); + YSTR("new_state"); dump_client_state(gen, new_state); + ) + ) + // clang-format on + + return 0; +} + +int +dump_error_message(yajl_gen gen, const char *reason) +{ + // clang-format off + YMAP( + YSTR("result"); YSTR("error"); + YSTR("reason"); YSTR(reason); + ) + // clang-format on + + return 0; +} diff --git a/suckless/dwm/patch/ipc/yajl_dumps.h b/suckless/dwm/patch/ipc/yajl_dumps.h new file mode 100644 index 00000000..65460030 --- /dev/null +++ b/suckless/dwm/patch/ipc/yajl_dumps.h @@ -0,0 +1,65 @@ +#ifndef YAJL_DUMPS_H_ +#define YAJL_DUMPS_H_ + +#include +#include + +#define YSTR(str) yajl_gen_string(gen, (unsigned char *)str, strlen(str)) +#define YINT(num) yajl_gen_integer(gen, num) +#define YDOUBLE(num) yajl_gen_double(gen, num) +#define YBOOL(v) yajl_gen_bool(gen, v) +#define YNULL() yajl_gen_null(gen) +#define YARR(body) \ + { \ + yajl_gen_array_open(gen); \ + body; \ + yajl_gen_array_close(gen); \ + } +#define YMAP(body) \ + { \ + yajl_gen_map_open(gen); \ + body; \ + yajl_gen_map_close(gen); \ + } + +int dump_tag(yajl_gen gen, const char *name, const int tag_mask); + +int dump_tags(yajl_gen gen, int tags_len); + +int dump_client(yajl_gen gen, Client *c); + +int dump_monitor(yajl_gen gen, Monitor *mon, int is_selected); + +int dump_monitors(yajl_gen gen, Monitor *mons, Monitor *selmon); + +int dump_layouts(yajl_gen gen, const Layout layouts[], const int layouts_len); + +int dump_tag_state(yajl_gen gen, TagState state); + +int dump_tag_event(yajl_gen gen, int mon_num, TagState old_state, + TagState new_state); + +int dump_client_focus_change_event(yajl_gen gen, Client *old_client, + Client *new_client, int mon_num); + +int dump_layout_change_event(yajl_gen gen, const int mon_num, + const char *old_symbol, const Layout *old_layout, + const char *new_symbol, const Layout *new_layout); + +int dump_monitor_focus_change_event(yajl_gen gen, const int last_mon_num, + const int new_mon_num); + +int dump_focused_title_change_event(yajl_gen gen, const int mon_num, + const Window client_id, + const char *old_name, const char *new_name); + +int dump_client_state(yajl_gen gen, const ClientState *state); + +int dump_focused_state_change_event(yajl_gen gen, const int mon_num, + const Window client_id, + const ClientState *old_state, + const ClientState *new_state); + +int dump_error_message(yajl_gen gen, const char *reason); + +#endif // YAJL_DUMPS_H_ diff --git a/suckless/dwm/patch/keymodes.c b/suckless/dwm/patch/keymodes.c new file mode 100644 index 00000000..45af3c5e --- /dev/null +++ b/suckless/dwm/patch/keymodes.c @@ -0,0 +1,143 @@ +/* function implementations */ +void +clearcmd(const Arg *arg) +{ + unsigned int i; + + for (i = 0; i < LENGTH(cmdkeysym); i++) { + cmdkeysym[i] = 0; + cmdmod[i] = 0; + } +} + +void +grabkeys(void) +{ + if (keymode == INSERTMODE) { + grabdefkeys(); + } else if (keymode == COMMANDMODE) { + XUngrabKey(dpy, AnyKey, AnyModifier, root); + XGrabKey(dpy, AnyKey, AnyModifier, root, + True, GrabModeAsync, GrabModeAsync); + } +} + +int +isprotodel(Client *c) +{ + int n; + Atom *protocols; + int ret = 0; + + if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { + while (!ret && n--) + ret = protocols[n] == wmatom[WMDelete]; + XFree(protocols); + } + return ret; +} + + +void +keypress(XEvent *e) +{ + unsigned int i, j; + Arg a = {0}; + Bool ismatch = False, maybematch = False; + KeySym keysym; + XKeyEvent *ev; + + if (keymode == INSERTMODE) + keydefpress(e); + else if (keymode == COMMANDMODE) { + ev = &e->xkey; + keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); + if (keysym < XK_Shift_L || keysym > XK_Hyper_R) { + 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)); + ismatch = True; + break; + } + if (!ismatch) { + 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++) { + for (j = 0; j < LENGTH(cmdkeysym); j++) { + if (cmdkeysym[j] == commands[i].keysym[j] + && CLEANMASK(cmdmod[j]) == CLEANMASK(commands[i].mod[j])) + ismatch = True; + else if (cmdkeysym[j] == 0 + && cmdmod[j] == 0) { + ismatch = False; + maybematch = True; + break; + } else { + ismatch = False; + break; + } + } + if (ismatch) { + if (commands[i].func) + commands[i].func(&(commands[i].arg)); + clearcmd(&a); + break; + } + + } + if (!maybematch) + clearcmd(&a); + } + } + } +} + +void +onlyclient(const Arg *arg) +{ + Client *c; + XEvent ev; + + if (!selmon->sel) + return; + for (c = selmon->clients; c; c = c->next) { + if (c != selmon->sel && ISVISIBLE(c)) { + if (isprotodel(c)) { + ev.type = ClientMessage; + ev.xclient.window = c->win; + ev.xclient.message_type = wmatom[WMProtocols]; + ev.xclient.format = 32; + ev.xclient.data.l[0] = wmatom[WMDelete]; + ev.xclient.data.l[1] = CurrentTime; + XSendEvent(dpy, c->win, False, NoEventMask, &ev); + } + else { + XGrabServer(dpy); + XSetErrorHandler(xerrordummy); + XSetCloseDownMode(dpy, DestroyAll); + XKillClient(dpy, c->win); + XSync(dpy, False); + XSetErrorHandler(xerror); + XUngrabServer(dpy); + } + } + } +} + +void +setkeymode(const Arg *arg) +{ + Arg a = {0}; + + if (!arg) + return; + keymode = arg->ui; + clearcmd(&a); + grabkeys(); +} \ No newline at end of file diff --git a/suckless/dwm/patch/keymodes.h b/suckless/dwm/patch/keymodes.h new file mode 100644 index 00000000..3a131637 --- /dev/null +++ b/suckless/dwm/patch/keymodes.h @@ -0,0 +1,21 @@ +#define COMMANDMODE 1 +#define INSERTMODE 2 + +typedef struct { + unsigned int mod[4]; + KeySym keysym[4]; + void (*func)(const Arg *); + const Arg arg; +} Command; + +static void clearcmd(const Arg *arg); +static void grabkeys(void); +static int isprotodel(Client *c); +static void keypress(XEvent *e); +static void onlyclient(const Arg *arg); +static void setkeymode(const Arg *arg); + +/* variables */ +static unsigned int cmdmod[4]; +static unsigned int keymode = INSERTMODE; +static KeySym cmdkeysym[4]; \ No newline at end of file diff --git a/suckless/dwm/patch/killunsel.c b/suckless/dwm/patch/killunsel.c new file mode 100644 index 00000000..774847b8 --- /dev/null +++ b/suckless/dwm/patch/killunsel.c @@ -0,0 +1,27 @@ +void +killunsel(const Arg *arg) +{ + Client *i = NULL; + + if (!selmon->sel) + return; + + for (i = selmon->clients; i; i = i->next) { + if (ISVISIBLE(i) && i != selmon->sel) { + #if BAR_SYSTRAY_PATCH + if (!sendevent(i->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0, 0, 0)) + #else + if (!sendevent(i, wmatom[WMDelete])) + #endif // BAR_SYSTRAY_PATCH + { + XGrabServer(dpy); + XSetErrorHandler(xerrordummy); + XSetCloseDownMode(dpy, DestroyAll); + XKillClient(dpy, i->win); + XSync(dpy, False); + XSetErrorHandler(xerror); + XUngrabServer(dpy); + } + } + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/killunsel.h b/suckless/dwm/patch/killunsel.h new file mode 100644 index 00000000..4f38a6e4 --- /dev/null +++ b/suckless/dwm/patch/killunsel.h @@ -0,0 +1 @@ +static void killunsel(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/layout_bstack.c b/suckless/dwm/patch/layout_bstack.c new file mode 100644 index 00000000..be066476 --- /dev/null +++ b/suckless/dwm/patch/layout_bstack.c @@ -0,0 +1,74 @@ +static void +bstack(Monitor *m) +{ + unsigned int i, n; + 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; + + #if VANITYGAPS_PATCH + int oh, ov, ih, iv; + getgaps(m, &oh, &ov, &ih, &iv, &n); + #else + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + #endif // VANITYGAPS_PATCH + + if (n == 0) + return; + + #if VANITYGAPS_PATCH + 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) * m->mfact; + sx = mx; + sy = my + mh + ih; + } + #else + sx = mx = m->wx; + sy = my = m->wy; + sh = mh = m->wh; + sw = mw = m->ww; + + if (m->nmaster && n > m->nmaster) { + sh = mh * (1 - m->mfact); + mh = mh * m->mfact; + sy = my + mh; + } + #endif // VANITYGAPS_PATCH + + 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) { + #if CFACTS_PATCH + resize(c, mx, my, (mw / mfacts) * c->cfact + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); + #else + resize(c, mx, my, (mw / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); + #endif // CFACTS_PATCH + #if VANITYGAPS_PATCH + mx += WIDTH(c) + iv; + #else + mx += WIDTH(c); + #endif + } else { + #if CFACTS_PATCH + resize(c, sx, sy, (sw / sfacts) * c->cfact + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0); + #else + resize(c, sx, sy, (sw / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0); + #endif // CFACTS_PATCH + #if VANITYGAPS_PATCH + sx += WIDTH(c) + iv; + #else + sx += WIDTH(c); + #endif + } + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/layout_bstack.h b/suckless/dwm/patch/layout_bstack.h new file mode 100644 index 00000000..56c99ffe --- /dev/null +++ b/suckless/dwm/patch/layout_bstack.h @@ -0,0 +1 @@ +static void bstack(Monitor *m); \ No newline at end of file diff --git a/suckless/dwm/patch/layout_bstackhoriz.c b/suckless/dwm/patch/layout_bstackhoriz.c new file mode 100644 index 00000000..0f9042f1 --- /dev/null +++ b/suckless/dwm/patch/layout_bstackhoriz.c @@ -0,0 +1,76 @@ +static void +bstackhoriz(Monitor *m) +{ + unsigned int i, n; + 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; + + #if VANITYGAPS_PATCH + int oh, ov, ih, iv; + getgaps(m, &oh, &ov, &ih, &iv, &n); + #else + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + #endif // VANITYGAPS_PATCH + + if (n == 0) + return; + + #if VANITYGAPS_PATCH + 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) * m->mfact; + sy = my + mh + ih; + sh = m->wh - mh - 2*oh - ih * (n - m->nmaster); + } + #else + sx = mx = m->wx; + sy = my = m->wy; + sh = mh = m->wh; + sw = mw = m->ww; + + if (m->nmaster && n > m->nmaster) { + sh = mh * (1 - m->mfact); + mh = mh * m->mfact; + sy = my + mh; + sh = m->wh - mh; + } + #endif // VANITYGAPS_PATCH + + 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) { + #if CFACTS_PATCH + resize(c, mx, my, (mw / mfacts) * c->cfact + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); + #else + resize(c, mx, my, (mw / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); + #endif // CFACTS_PATCH + #if VANITYGAPS_PATCH + mx += WIDTH(c) + iv; + #else + mx += WIDTH(c); + #endif + } else { + #if CFACTS_PATCH + resize(c, sx, sy, sw - (2*c->bw), (sh / sfacts) * c->cfact + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0); + #else + resize(c, sx, sy, sw - (2*c->bw), (sh / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0); + #endif // CFACTS_PATCH + #if VANITYGAPS_PATCH + sy += HEIGHT(c) + ih; + #else + sy += HEIGHT(c); + #endif + } + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/layout_bstackhoriz.h b/suckless/dwm/patch/layout_bstackhoriz.h new file mode 100644 index 00000000..8dd0ebd2 --- /dev/null +++ b/suckless/dwm/patch/layout_bstackhoriz.h @@ -0,0 +1 @@ +static void bstackhoriz(Monitor *m); \ No newline at end of file diff --git a/suckless/dwm/patch/layout_centeredfloatingmaster.c b/suckless/dwm/patch/layout_centeredfloatingmaster.c new file mode 100644 index 00000000..756b41f4 --- /dev/null +++ b/suckless/dwm/patch/layout_centeredfloatingmaster.c @@ -0,0 +1,94 @@ +void +centeredfloatingmaster(Monitor *m) +{ + unsigned int i, n; + float mfacts, sfacts; + int mrest, srest; + int mx = 0, my = 0, mh = 0, mw = 0; + int sx = 0, sy = 0, sh = 0, sw = 0; + Client *c; + + #if VANITYGAPS_PATCH + float mivf = 1.0; // master inner vertical gap factor + int oh, ov, ih, iv; + getgaps(m, &oh, &ov, &ih, &iv, &n); + #else + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + #endif // VANITYGAPS_PATCH + + if (n == 0) + return; + + #if VANITYGAPS_PATCH + 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; + } + #else + sx = mx = m->wx; + sy = my = m->wy; + sh = mh = m->wh; + sw = mw = m->ww; + + if (m->nmaster && n > m->nmaster) { + /* go mfact box in the center if more than nmaster clients */ + if (m->ww > m->wh) { + mw = m->ww * m->mfact; + mh = m->wh * 0.9; + } else { + mw = m->ww * 0.9; + mh = m->wh * m->mfact; + } + mx = m->wx + (m->ww - mw) / 2; + my = m->wy + (m->wh - mh) / 2; + } + #endif // VANITYGAPS_PATCH + + 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 */ + #if CFACTS_PATCH + resize(c, mx, my, (mw / mfacts) * c->cfact + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); + #else + resize(c, mx, my, (mw / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); + #endif // CFACTS_PATCH + #if VANITYGAPS_PATCH + mx += WIDTH(c) + iv*mivf; + #else + mx += WIDTH(c); + #endif + } else { + /* stack clients are stacked horizontally */ + #if CFACTS_PATCH + resize(c, sx, sy, (sw / sfacts) * c->cfact + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0); + #else + resize(c, sx, sy, (sw / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0); + #endif // CFACTS_PATCH + #if VANITYGAPS_PATCH + sx += WIDTH(c) + iv; + #else + sx += WIDTH(c); + #endif + } +} diff --git a/suckless/dwm/patch/layout_centeredfloatingmaster.h b/suckless/dwm/patch/layout_centeredfloatingmaster.h new file mode 100644 index 00000000..e4147b3b --- /dev/null +++ b/suckless/dwm/patch/layout_centeredfloatingmaster.h @@ -0,0 +1 @@ +static void centeredfloatingmaster(Monitor *m); \ No newline at end of file diff --git a/suckless/dwm/patch/layout_centeredmaster.c b/suckless/dwm/patch/layout_centeredmaster.c new file mode 100644 index 00000000..a72eb070 --- /dev/null +++ b/suckless/dwm/patch/layout_centeredmaster.c @@ -0,0 +1,159 @@ +void +centeredmaster(Monitor *m) +{ + unsigned int i, n; + 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; + + #if VANITYGAPS_PATCH + int oh, ov, ih, iv; + getgaps(m, &oh, &ov, &ih, &iv, &n); + #else + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + #endif // VANITYGAPS_PATCH + + if (n == 0) + return; + + /* initialize areas */ + #if VANITYGAPS_PATCH + 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; + mx += lw + iv; + } else { + /* ||<---M--->|<-S->|| */ + mw = (mw - iv) * m->mfact; + lw = m->ww - mw - iv - 2*ov; + } + rw = lw; + lx = m->wx + ov; + ly = m->wy + oh; + rx = mx + mw + iv; + ry = m->wy + oh; + } + #else + mx = m->wx; + my = m->wy; + mh = m->wh; + mw = m->ww; + lh = m->wh; + rh = m->wh; + + 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 * m->mfact; + lw = (m->ww - mw) / 2; + mx += lw; + } else { + /* ||<---M--->|<-S->|| */ + mw = mw * m->mfact; + lw = m->ww - mw; + } + rw = lw; + lx = m->wx; + ly = m->wy; + rx = mx + mw; + ry = m->wy; + } + #endif // VANITYGAPS_PATCH + + /* calculate facts */ + #if CFACTS_PATCH + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { + if (!m->nmaster || n < m->nmaster) + mfacts += c->cfact; // total factor of master area + 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 / mfacts; + else if ((n - m->nmaster) % 2) + ltotal += lh * (c->cfact / lfacts); + else + rtotal += rh * (c->cfact / rfacts); + #else + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { + if (!m->nmaster || n < m->nmaster) + mfacts += 1; + else if ((n - m->nmaster) % 2) + lfacts += 1; // total factor of left hand stack area + else + rfacts += 1; // 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 / mfacts; + else if ((n - m->nmaster) % 2) + ltotal += lh / lfacts; + else + rtotal += rh / rfacts; + #endif // CFACTS_PATCH + + 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 */ + #if CFACTS_PATCH + resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) * c->cfact + (i < mrest ? 1 : 0) - (2*c->bw), 0); + #else + resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0); + #endif // CFACTS_PATCH + #if VANITYGAPS_PATCH + my += HEIGHT(c) + ih; + #else + my += HEIGHT(c); + #endif + } else { + /* stack clients are stacked vertically */ + if ((i - m->nmaster) % 2 ) { + #if CFACTS_PATCH + resize(c, lx, ly, lw - (2*c->bw), (lh / lfacts) * c->cfact + ((i - 2*m->nmaster) < 2*lrest ? 1 : 0) - (2*c->bw), 0); + #else + resize(c, lx, ly, lw - (2*c->bw), (lh / lfacts) + ((i - 2*m->nmaster) < 2*lrest ? 1 : 0) - (2*c->bw), 0); + #endif // CFACTS_PATCH + #if VANITYGAPS_PATCH + ly += HEIGHT(c) + ih; + #else + ly += HEIGHT(c); + #endif + } else { + #if CFACTS_PATCH + resize(c, rx, ry, rw - (2*c->bw), (rh / rfacts) * c->cfact + ((i - 2*m->nmaster) < 2*rrest ? 1 : 0) - (2*c->bw), 0); + #else + resize(c, rx, ry, rw - (2*c->bw), (rh / rfacts) + ((i - 2*m->nmaster) < 2*rrest ? 1 : 0) - (2*c->bw), 0); + #endif // CFACTS_PATCH + #if VANITYGAPS_PATCH + ry += HEIGHT(c) + ih; + #else + ry += HEIGHT(c); + #endif + } + } + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/layout_centeredmaster.h b/suckless/dwm/patch/layout_centeredmaster.h new file mode 100644 index 00000000..b0472127 --- /dev/null +++ b/suckless/dwm/patch/layout_centeredmaster.h @@ -0,0 +1 @@ +static void centeredmaster(Monitor *m); \ No newline at end of file diff --git a/suckless/dwm/patch/layout_columns.c b/suckless/dwm/patch/layout_columns.c new file mode 100644 index 00000000..bcdaa110 --- /dev/null +++ b/suckless/dwm/patch/layout_columns.c @@ -0,0 +1,73 @@ +static void +col(Monitor *m) +{ + unsigned int i, n; + 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; + + #if VANITYGAPS_PATCH + int oh, ov, ih, iv; + getgaps(m, &oh, &ov, &ih, &iv, &n); + #else + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + #endif // VANITYGAPS_PATCH + + if (n == 0) + return; + + #if VANITYGAPS_PATCH + 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) { + sw = (mw - iv) * (1 - m->mfact); + mw = (mw - iv) * m->mfact; + sx = mx + mw + iv * m->nmaster; + } + #else + sx = mx = m->wx; + sy = my = m->wy; + sh = mh = m->wh; + sw = mw = m->ww; + + if (m->nmaster && n > m->nmaster) { + sw = mw * (1 - m->mfact); + mw = mw * m->mfact; + sx = mx + mw; + } + #endif // VANITYGAPS_PATCH + + 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) { + #if CFACTS_PATCH + resize(c, mx, my, (mw / mfacts) * c->cfact + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); + #else + resize(c, mx, my, (mw / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); + #endif // CFACTS_PATCH + #if VANITYGAPS_PATCH + mx += WIDTH(c) + iv; + #else + mx += WIDTH(c); + #endif + } else { + #if CFACTS_PATCH + resize(c, sx, sy, sw - (2*c->bw), (sh / sfacts) * c->cfact + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0); + #else + resize(c, sx, sy, sw - (2*c->bw), (sh / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0); + #endif // CFACTS_PATCH + #if VANITYGAPS_PATCH + sy += HEIGHT(c) + ih; + #else + sy += HEIGHT(c); + #endif + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/layout_columns.h b/suckless/dwm/patch/layout_columns.h new file mode 100644 index 00000000..8f64a094 --- /dev/null +++ b/suckless/dwm/patch/layout_columns.h @@ -0,0 +1 @@ +static void col(Monitor *); \ No newline at end of file diff --git a/suckless/dwm/patch/layout_deck.c b/suckless/dwm/patch/layout_deck.c new file mode 100644 index 00000000..6f2027d1 --- /dev/null +++ b/suckless/dwm/patch/layout_deck.c @@ -0,0 +1,66 @@ +static void +deck(Monitor *m) +{ + unsigned int i, n; + 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; + + #if VANITYGAPS_PATCH + int oh, ov, ih, iv; + getgaps(m, &oh, &ov, &ih, &iv, &n); + #else + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + #endif // VANITYGAPS_PATCH + + if (n == 0) + return; + + #if VANITYGAPS_PATCH + 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) * m->mfact; + sx = mx + mw + iv; + sh = m->wh - 2*oh; + } + #else + sx = mx = m->wx; + sy = my = m->wy; + sh = mh = m->wh; + sw = mw = m->ww; + + if (m->nmaster && n > m->nmaster) { + sw = mw * (1 - m->mfact); + mw = mw * m->mfact; + sx = mx + mw; + } + #endif // VANITYGAPS_PATCH + + 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) { + #if CFACTS_PATCH + resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) * c->cfact + (i < mrest ? 1 : 0) - (2*c->bw), 0); + #else + resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0); + #endif // CFACTS_PATCH + #if VANITYGAPS_PATCH + my += HEIGHT(c) + ih; + #else + my += HEIGHT(c); + #endif + } else { + resize(c, sx, sy, sw - (2*c->bw), sh - (2*c->bw), 0); + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/layout_deck.h b/suckless/dwm/patch/layout_deck.h new file mode 100644 index 00000000..abedeb2a --- /dev/null +++ b/suckless/dwm/patch/layout_deck.h @@ -0,0 +1 @@ +static void deck(Monitor *m); \ No newline at end of file diff --git a/suckless/dwm/patch/layout_facts.c b/suckless/dwm/patch/layout_facts.c new file mode 100644 index 00000000..e5beb4b6 --- /dev/null +++ b/suckless/dwm/patch/layout_facts.c @@ -0,0 +1,51 @@ +#if CFACTS_PATCH +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 +} +#else +void +getfacts(Monitor *m, int msize, int ssize, float *mf, float *sf, int *mr, int *sr) +{ + unsigned int n; + float mfacts, sfacts; + int mtotal = 0, stotal = 0; + Client *c; + + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + mfacts = MIN(n, m->nmaster); + sfacts = n - m->nmaster; + + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) + if (n < m->nmaster) + mtotal += msize / mfacts; + else + stotal += ssize / sfacts; + + *mf = mfacts; // total factor of master area + *sf = sfacts; // total factor of stack area + *mr = msize - mtotal; // the remainder (rest) of pixels after an even master split + *sr = ssize - stotal; // the remainder (rest) of pixels after an even stack split +} +#endif // CFACTS_PATCH diff --git a/suckless/dwm/patch/layout_fibonacci.c b/suckless/dwm/patch/layout_fibonacci.c new file mode 100644 index 00000000..87a1bdf3 --- /dev/null +++ b/suckless/dwm/patch/layout_fibonacci.c @@ -0,0 +1,190 @@ +#if VANITYGAPS_PATCH +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 = 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); + } +} +#else +void +fibonacci(Monitor *m, int s) +{ + unsigned int i, n; + int nx, ny, nw, nh; + int nv, hrest = 0, wrest = 0, r = 1; + Client *c; + + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if (n == 0) + return; + + nx = m->wx; + ny = m->wy; + nw = m->ww; + nh = m->wh; + + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) { + if (r) { + if ((i % 2 && nh / 2 <= (bh + 2*c->bw)) + || (!(i % 2) && nw / 2 <= (bh + 2*c->bw))) { + r = 0; + } + if (r && i < n - 1) { + if (i % 2) { + nv = nh / 2; + hrest = nh - 2*nv; + nh = nv; + } else { + nv = nw / 2; + wrest = nw - 2*nv; + nw = nv; + } + + if ((i % 4) == 2 && !s) + nx += nw; + else if ((i % 4) == 3 && !s) + ny += nh; + } + + if ((i % 4) == 0) { + if (s) { + ny += nh; + nh += hrest; + } + else { + nh -= hrest; + ny -= nh; + } + } + else if ((i % 4) == 1) { + nx += nw; + nw += wrest; + } + else if ((i % 4) == 2) { + ny += nh; + nh += hrest; + if (i < n - 1) + nw += wrest; + } + else if ((i % 4) == 3) { + if (s) { + nx += nw; + nw -= wrest; + } else { + nw -= wrest; + nx -= nw; + nh += hrest; + } + } + if (i == 0) { + if (n != 1) { + nw = m->ww - m->ww * (1 - m->mfact); + wrest = 0; + } + ny = m->wy; + } + else if (i == 1) + nw = m->ww - nw; + i++; + } + + resize(c, nx, ny, nw - (2*c->bw), nh - (2*c->bw), False); + } +} +#endif + +#if FIBONACCI_DWINDLE_LAYOUT +static void +dwindle(Monitor *m) +{ + fibonacci(m, 1); +} +#endif + +#if FIBONACCI_SPIRAL_LAYOUT +static void +spiral(Monitor *m) +{ + fibonacci(m, 0); +} +#endif diff --git a/suckless/dwm/patch/layout_fibonacci.h b/suckless/dwm/patch/layout_fibonacci.h new file mode 100644 index 00000000..a15eb76c --- /dev/null +++ b/suckless/dwm/patch/layout_fibonacci.h @@ -0,0 +1,7 @@ +#if FIBONACCI_DWINDLE_LAYOUT +static void dwindle(Monitor *m); +#endif // FIBONACCI_DWINDLE_LAYOUT +static void fibonacci(Monitor *m, int s); +#if FIBONACCI_SPIRAL_LAYOUT +static void spiral(Monitor *m); +#endif // FIBONACCI_SPIRAL_LAYOUT \ No newline at end of file diff --git a/suckless/dwm/patch/layout_flextile-deluxe.c b/suckless/dwm/patch/layout_flextile-deluxe.c new file mode 100644 index 00000000..3f5cc27c --- /dev/null +++ b/suckless/dwm/patch/layout_flextile-deluxe.c @@ -0,0 +1,890 @@ +typedef struct { + void (*arrange)(Monitor *, int, int, int, int, int, int, int); +} LayoutArranger; + +typedef struct { + void (*arrange)(Monitor *, int, int, int, int, int, int, int, int, int); +} TileArranger; + +static const LayoutArranger flexlayouts[] = { + { layout_no_split }, + { layout_split_vertical }, + { layout_split_horizontal }, + { layout_split_centered_vertical }, + { layout_split_centered_horizontal }, + { layout_split_vertical_dual_stack }, + { layout_split_horizontal_dual_stack }, + { layout_floating_master }, + { layout_split_vertical_fixed }, + { layout_split_horizontal_fixed }, + { layout_split_centered_vertical_fixed }, + { layout_split_centered_horizontal_fixed }, + { layout_split_vertical_dual_stack_fixed }, + { layout_split_horizontal_dual_stack_fixed }, + { layout_floating_master_fixed }, +}; + +static const TileArranger flextiles[] = { + { arrange_top_to_bottom }, + { arrange_left_to_right }, + { arrange_monocle }, + { arrange_gapplessgrid }, + { arrange_gapplessgrid_alt1 }, + { arrange_gapplessgrid_alt2 }, + { arrange_gridmode }, + { arrange_horizgrid }, + { arrange_dwindle }, + { arrange_spiral }, + { arrange_tatami }, +}; + +static void +getfactsforrange(Monitor *m, int an, int ai, int size, int *rest, float *fact) +{ + int i; + float facts; + Client *c; + int total = 0; + + facts = 0; + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i >= ai && i < (ai + an)) + #if CFACTS_PATCH + facts += c->cfact; + #else + facts += 1; + #endif // CFACTS_PATCH + + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i >= ai && i < (ai + an)) + #if CFACTS_PATCH + total += size * (c->cfact / facts); + #else + total += size / facts; + #endif // CFACTS_PATCH + + *rest = size - total; + *fact = facts; +} + +#if IPC_PATCH || DWMC_PATCH +static void +setlayoutaxisex(const Arg *arg) +{ + int axis, arr; + + axis = arg->i & 0x3; // lower two bytes indicates layout, master or stack1-2 + arr = ((arg->i & 0xFC) >> 2); // remaining six upper bytes indicate arrangement + + if ((axis == 0 && abs(arr) > LAYOUT_LAST) + || (axis > 0 && (arr > AXIS_LAST || arr < 0))) + arr = 0; + + selmon->ltaxis[axis] = arr; + #if PERTAG_PATCH + selmon->pertag->ltaxis[selmon->pertag->curtag][axis] = selmon->ltaxis[axis]; + #endif // PERTAG_PATCH + arrange(selmon); +} +#endif // IPC_PATCH | DWMC_PATCH + +static void +layout_no_split(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) +{ + (&flextiles[m->ltaxis[m->nmaster >= n ? MASTER : STACK]])->arrange(m, x, y, h, w, ih, iv, n, n, 0); +} + +static void +layout_split_vertical(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) +{ + /* Split master into master + stack if we have enough clients */ + if (m->nmaster && n > m->nmaster) { + layout_split_vertical_fixed(m, x, y, h, w, ih, iv, n); + } else { + layout_no_split(m, x, y, h, w, ih, iv, n); + } +} + +static void +layout_split_vertical_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) +{ + int sw, sx; + + sw = (w - iv) * (1 - m->mfact); + w = (w - iv) * m->mfact; + if (m->ltaxis[LAYOUT] < 0) { // mirror + sx = x; + x += sw + iv; + } else { + sx = x + w + iv; + } + + (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, h, w, ih, iv, n, m->nmaster, 0); + (&flextiles[m->ltaxis[STACK]])->arrange(m, sx, y, h, sw, ih, iv, n, n - m->nmaster, m->nmaster); +} + +static void +layout_split_vertical_dual_stack(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) +{ + /* Split master into master + stack if we have enough clients */ + if (!m->nmaster || n <= m->nmaster) { + layout_no_split(m, x, y, h, w, ih, iv, n); + } else if (n <= m->nmaster + (m->nstack ? m->nstack : 1)) { + layout_split_vertical(m, x, y, h, w, ih, iv, n); + } else { + layout_split_vertical_dual_stack_fixed(m, x, y, h, w, ih, iv, n); + } +} + +static void +layout_split_vertical_dual_stack_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) +{ + int sh, sw, sx, oy, sc; + + if (m->nstack) + sc = m->nstack; + else + sc = (n - m->nmaster) / 2 + ((n - m->nmaster) % 2 > 0 ? 1 : 0); + + sw = (w - iv) * (1 - m->mfact); + sh = (h - ih) / 2; + w = (w - iv) * m->mfact; + oy = y + sh + ih; + if (m->ltaxis[LAYOUT] < 0) { // mirror + sx = x; + x += sw + iv; + } else { + sx = x + w + iv; + } + + (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, h, w, ih, iv, n, m->nmaster, 0); + (&flextiles[m->ltaxis[STACK]])->arrange(m, sx, y, sh, sw, ih, iv, n, sc, m->nmaster); + (&flextiles[m->ltaxis[STACK2]])->arrange(m, sx, oy, sh, sw, ih, iv, n, n - m->nmaster - sc, m->nmaster + sc); +} + +static void +layout_split_horizontal(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) +{ + /* Split master into master + stack if we have enough clients */ + if (m->nmaster && n > m->nmaster) { + layout_split_horizontal_fixed(m, x, y, h, w, ih, iv, n); + } else { + layout_no_split(m, x, y, h, w, ih, iv, n); + } +} + +static void +layout_split_horizontal_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) +{ + int sh, sy; + + sh = (h - ih) * (1 - m->mfact); + h = (h - ih) * m->mfact; + if (m->ltaxis[LAYOUT] < 0) { // mirror + sy = y; + y += sh + ih; + } else { + sy = y + h + ih; + } + + (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, h, w, ih, iv, n, m->nmaster, 0); + (&flextiles[m->ltaxis[STACK]])->arrange(m, x, sy, sh, w, ih, iv, n, n - m->nmaster, m->nmaster); +} + +static void +layout_split_horizontal_dual_stack(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) +{ + /* Split master into master + stack if we have enough clients */ + if (!m->nmaster || n <= m->nmaster) { + layout_no_split(m, x, y, h, w, ih, iv, n); + } else if (n <= m->nmaster + (m->nstack ? m->nstack : 1)) { + layout_split_horizontal(m, x, y, h, w, ih, iv, n); + } else { + layout_split_horizontal_dual_stack_fixed(m, x, y, h, w, ih, iv, n); + } +} + +static void +layout_split_horizontal_dual_stack_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) +{ + int sh, sy, ox, sc; + + if (m->nstack) + sc = m->nstack; + else + sc = (n - m->nmaster) / 2 + ((n - m->nmaster) % 2 > 0 ? 1 : 0); + + sh = (h - ih) * (1 - m->mfact); + h = (h - ih) * m->mfact; + sw = (w - iv) / 2; + ox = x + sw + iv; + if (m->ltaxis[LAYOUT] < 0) { // mirror + sy = y; + y += sh + ih; + } else { + sy = y + h + ih; + } + + (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, h, w, ih, iv, n, m->nmaster, 0); + (&flextiles[m->ltaxis[STACK]])->arrange(m, x, sy, sh, sw, ih, iv, n, sc, m->nmaster); + (&flextiles[m->ltaxis[STACK2]])->arrange(m, ox, sy, sh, sw, ih, iv, n, n - m->nmaster - sc, m->nmaster + sc); +} + +static void +layout_split_centered_vertical(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) +{ + /* Split master into master + stack if we have enough clients */ + if (!m->nmaster || n <= m->nmaster) { + layout_no_split(m, x, y, h, w, ih, iv, n); + } else if (n <= m->nmaster + (m->nstack ? m->nstack : 1)) { + layout_split_vertical(m, x, y, h, w, ih, iv, n); + } else { + layout_split_centered_vertical_fixed(m, x, y, h, w, ih, iv, n); + } +} + +static void +layout_split_centered_vertical_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) +{ + int sw, sx, ox, sc; + + if (m->nstack) + sc = m->nstack; + else + sc = (n - m->nmaster) / 2 + ((n - m->nmaster) % 2 > 0 ? 1 : 0); + + sw = (w - 2*iv) * (1 - m->mfact) / 2; + w = (w - 2*iv) * m->mfact; + if (m->ltaxis[LAYOUT] < 0) { // mirror + sx = x; + x += sw + iv; + ox = x + w + iv; + } else { + ox = x; + x += sw + iv; + sx = x + w + iv; + } + + (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, h, w, ih, iv, n, m->nmaster, 0); + (&flextiles[m->ltaxis[STACK]])->arrange(m, sx, y, h, sw, ih, iv, n, sc, m->nmaster); + (&flextiles[m->ltaxis[STACK2]])->arrange(m, ox, y, h, sw, ih, iv, n, n - m->nmaster - sc, m->nmaster + sc); +} + +static void +layout_split_centered_horizontal(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) +{ + /* Split master into master + stack if we have enough clients */ + if (!m->nmaster || n <= m->nmaster) { + layout_no_split(m, x, y, h, w, ih, iv, n); + } else if (n <= m->nmaster + (m->nstack ? m->nstack : 1)) { + layout_split_horizontal(m, x, y, h, w, ih, iv, n); + } else { + layout_split_centered_horizontal_fixed(m, x, y, h, w, ih, iv, n); + } +} + +static void +layout_split_centered_horizontal_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) +{ + int sh, sy, oy, sc; + + if (m->nstack) + sc = m->nstack; + else + sc = (n - m->nmaster) / 2 + ((n - m->nmaster) % 2 > 0 ? 1 : 0); + + sh = (h - 2*ih) * (1 - m->mfact) / 2; + h = (h - 2*ih) * m->mfact; + if (m->ltaxis[LAYOUT] < 0) { // mirror + sy = y; + y += sh + ih; + oy = y + h + ih; + } else { + oy = y; + y += sh + ih; + sy = y + h + ih; + } + + (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, h, w, ih, iv, n, m->nmaster, 0); + (&flextiles[m->ltaxis[STACK]])->arrange(m, x, sy, sh, w, ih, iv, n, sc, m->nmaster); + (&flextiles[m->ltaxis[STACK2]])->arrange(m, x, oy, sh, w, ih, iv, n, n - m->nmaster - sc, m->nmaster + sc); +} + +static void +layout_floating_master(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) +{ + /* Split master into master + stack if we have enough clients */ + if (!m->nmaster || n <= m->nmaster) { + layout_no_split(m, x, y, h, w, ih, iv, n); + } else { + layout_floating_master_fixed(m, x, y, h, w, ih, iv, n); + } +} + +static void +layout_floating_master_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n) +{ + int mh, mw; + + /* Draw stack area first */ + (&flextiles[m->ltaxis[STACK]])->arrange(m, x, y, h, w, ih, iv, n, n - m->nmaster, m->nmaster); + + if (w > h) { + mw = w * m->mfact; + mh = h * 0.9; + } else { + mw = w * 0.9; + mh = h * m->mfact; + } + x = x + (w - mw) / 2; + y = y + (h - mh) / 2; + + (&flextiles[m->ltaxis[MASTER]])->arrange(m, x, y, mh, mw, ih, iv, n, m->nmaster, 0); +} + +static void +arrange_left_to_right(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) +{ + int i, rest; + float facts, fact = 1; + Client *c; + + if (ai + an > n) + an = n - ai; + + w -= iv * (an - 1); + getfactsforrange(m, an, ai, w, &rest, &facts); + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { + if (i >= ai && i < (ai + an)) { + #if CFACTS_PATCH + fact = c->cfact; + #endif // CFACTS_PATCH + resize(c, x, y, w * (fact / facts) + ((i - ai) < rest ? 1 : 0) - (2*c->bw), h - (2*c->bw), 0); + x += WIDTH(c) + iv; + } + } +} + +static void +arrange_top_to_bottom(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) +{ + int i, rest; + float facts, fact = 1; + Client *c; + + if (ai + an > n) + an = n - ai; + + h -= ih * (an - 1); + getfactsforrange(m, an, ai, h, &rest, &facts); + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { + if (i >= ai && i < (ai + an)) { + #if CFACTS_PATCH + fact = c->cfact; + #endif // CFACTS_PATCH + resize(c, x, y, w - (2*c->bw), h * (fact / facts) + ((i - ai) < rest ? 1 : 0) - (2*c->bw), 0); + y += HEIGHT(c) + ih; + } + } +} + +static void +arrange_monocle(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) +{ + int i; + Client *c; + + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i >= ai && i < (ai + an)) + resize(c, x, y, w - (2*c->bw), h - (2*c->bw), 0); +} + +static void +arrange_gridmode(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) +{ + int i, cols, rows, ch, cw, cx, cy, cc, cr, chrest, cwrest; // counters + Client *c; + + /* grid dimensions */ + for (rows = 0; rows <= an/2; rows++) + if (rows*rows >= an) + break; + cols = (rows && (rows - 1) * rows >= an) ? rows - 1 : rows; + + /* window geoms (cell height/width) */ + ch = (h - ih * (rows - 1)) / (rows ? rows : 1); + cw = (w - iv * (cols - 1)) / (cols ? cols : 1); + chrest = h - ih * (rows - 1) - ch * rows; + cwrest = w - iv * (cols - 1) - cw * cols; + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { + if (i >= ai && i < (ai + an)) { + cc = ((i - ai) / rows); // client column number + cr = ((i - ai) % rows); // client row number + cx = x + cc * (cw + iv) + MIN(cc, cwrest); + cy = y + 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); + } + } +} + +static void +arrange_horizgrid(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) +{ + int ntop, nbottom, rh, rest; + + /* Exception when there is only one client; don't split into two rows */ + if (an == 1) { + arrange_monocle(m, x, y, h, w, ih, iv, n, an, ai); + return; + } + + ntop = an / 2; + nbottom = an - ntop; + rh = (h - ih) / 2; + rest = h - ih - rh * 2; + arrange_left_to_right(m, x, y, rh + rest, w, ih, iv, n, ntop, ai); + arrange_left_to_right(m, x, y + rh + ih + rest, rh, w, ih, iv, n, nbottom, ai + ntop); +} + +static void +arrange_gapplessgrid(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) +{ + int i, cols, rows, ch, cw, cn, rn, cc, rrest, crest; // counters + Client *c; + + /* grid dimensions */ + for (cols = 1; cols <= an/2; cols++) + if (cols*cols >= an) + break; + if (an == 5) /* set layout against the general calculation: not 1:2:2, but 2:3 */ + cols = 2; + rows = an/cols; + cn = rn = cc = 0; // reset column no, row no, client count + + ch = (h - ih * (rows - 1)) / rows; + rrest = (h - ih * (rows - 1)) - ch * rows; + cw = (w - iv * (cols - 1)) / cols; + crest = (w - iv * (cols - 1)) - cw * cols; + + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { + if (i >= ai && i < (ai + an)) { + if (cc/rows + 1 > cols - an%cols) { + rows = an/cols + 1; + ch = (h - ih * (rows - 1)) / rows; + rrest = (h - 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++; + cc++; + if (rn >= rows) { + rn = 0; + x += cw + ih + (cn < crest ? 1 : 0); + cn++; + } + } + } +} + +/* This version of gappless grid fills rows first */ +static void +arrange_gapplessgrid_alt1(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) +{ + int i, cols, rows, rest, ch; + + /* grid dimensions */ + for (cols = 1; cols <= an/2; cols++) + if (cols*cols >= an) + break; + rows = (cols && (cols - 1) * cols >= an) ? cols - 1 : cols; + ch = (h - ih * (rows - 1)) / (rows ? rows : 1); + rest = (h - ih * (rows - 1)) - ch * rows; + + for (i = 0; i < rows; i++) { + arrange_left_to_right(m, x, y, ch + (i < rest ? 1 : 0), w, ih, iv, n, MIN(cols, an - i*cols), ai + i*cols); + y += ch + (i < rest ? 1 : 0) + ih; + } +} + +/* This version of gappless grid fills columns first */ +static void +arrange_gapplessgrid_alt2(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) +{ + int i, cols, rows, rest, cw; + + /* grid dimensions */ + for (rows = 0; rows <= an/2; rows++) + if (rows*rows >= an) + break; + cols = (rows && (rows - 1) * rows >= an) ? rows - 1 : rows; + cw = (w - iv * (cols - 1)) / (cols ? cols : 1); + rest = (w - iv * (cols - 1)) - cw * cols; + + for (i = 0; i < cols; i++) { + arrange_top_to_bottom(m, x, y, h, cw + (i < rest ? 1 : 0), ih, iv, n, MIN(rows, an - i*rows), ai + i*rows); + x += cw + (i < rest ? 1 : 0) + iv; + } +} + +static void +arrange_fibonacci(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai, int s) +{ + int i, j, nv, hrest = 0, wrest = 0, nx = x, ny = y, nw = w, nh = h, r = 1; + Client *c; + + for (i = 0, j = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), j++) { + if (j >= ai && j < (ai + an)) { + 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 < an - 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 (an != 1) { + nw = (w - iv) - (w - iv) * (1 - m->mfact); + wrest = 0; + } + ny = y; + } else if (i == 1) + nw = w - nw - iv; + i++; + } + + resize(c, nx, ny, nw - 2 * c->bw, nh - 2*c->bw, False); + } + } +} + +static void +arrange_dwindle(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) +{ + arrange_fibonacci(m, x, y, h, w, ih, iv, n, an, ai, 1); +} + +static void +arrange_spiral(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) +{ + arrange_fibonacci(m, x, y, h, w, ih, iv, n, an, ai, 0); +} + +static void +arrange_tatami(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n, int an, int ai) +{ + unsigned int i, j, nx, ny, nw, nh, tnx, tny, tnw, tnh, nhrest, hrest, wrest, areas, mats, cats; + Client *c; + + nx = x; + ny = y; + nw = w; + nh = h; + + mats = an / 5; + cats = an % 5; + hrest = 0; + wrest = 0; + + areas = mats + (cats > 0); + nh = (h - ih * (areas - 1)) / areas; + nhrest = (h - ih * (areas - 1)) % areas; + + for (i = 0, j = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), j++) { + if (j >= ai && j < (ai + an)) { + + tnw = nw; + tnx = nx; + tnh = nh; + tny = ny; + + if (j < ai + cats) { + /* Arrange cats (all excess clients that can't be tiled as mats). Cats sleep on mats. */ + + switch (cats) { + case 1: // fill + break; + case 2: // up and down + if ((i % 5) == 0) //up + tnh = (nh - ih) / 2 + (nh - ih) % 2; + else if ((i % 5) == 1) { //down + tny += (nh - ih) / 2 + (nh - ih) % 2 + ih; + tnh = (nh - ih) / 2; + } + break; + case 3: //bottom, up-left and up-right + if ((i % 5) == 0) { // up-left + tnw = (nw - iv) / 2 + (nw - iv) % 2; + tnh = (nh - ih) * 2 / 3 + (nh - ih) * 2 % 3; + } else if ((i % 5) == 1) { // up-right + tnx += (nw - iv) / 2 + (nw - iv) % 2 + iv; + tnw = (nw - iv) / 2; + tnh = (nh - ih) * 2 / 3 + (nh - ih) * 2 % 3; + } else if ((i % 5) == 2) { //bottom + tnh = (nh - ih) / 3; + tny += (nh - ih) * 2 / 3 + (nh - ih) * 2 % 3 + ih; + } + break; + case 4: // bottom, left, right and top + if ((i % 5) == 0) { //top + hrest = (nh - 2 * ih) % 4; + tnh = (nh - 2 * ih) / 4 + (hrest ? 1 : 0); + } else if ((i % 5) == 1) { // left + tnw = (nw - iv) / 2 + (nw - iv) % 2; + tny += (nh - 2 * ih) / 4 + (hrest ? 1 : 0) + ih; + tnh = (nh - 2 * ih) * 2 / 4 + (hrest > 1 ? 1 : 0); + } else if ((i % 5) == 2) { // right + tnx += (nw - iv) / 2 + (nw - iv) % 2 + iv; + tnw = (nw - iv) / 2; + tny += (nh - 2 * ih) / 4 + (hrest ? 1 : 0) + ih; + tnh = (nh - 2 * ih) * 2 / 4 + (hrest > 1 ? 1 : 0); + } else if ((i % 5) == 3) { // bottom + tny += (nh - 2 * ih) / 4 + (hrest ? 1 : 0) + (nh - 2 * ih) * 2 / 4 + (hrest > 1 ? 1 : 0) + 2 * ih; + tnh = (nh - 2 * ih) / 4 + (hrest > 2 ? 1 : 0); + } + break; + } + + } else { + /* Arrange mats. One mat is a collection of five clients arranged tatami style */ + + if (((i - cats) % 5) == 0) { + if ((cats > 0) || ((i - cats) >= 5)) { + tny = ny = ny + nh + (nhrest > 0 ? 1 : 0) + ih; + --nhrest; + } + } + + switch ((i - cats) % 5) { + case 0: // top-left-vert + wrest = (nw - 2 * iv) % 3; + hrest = (nh - 2 * ih) % 3; + tnw = (nw - 2 * iv) / 3 + (wrest ? 1 : 0); + tnh = (nh - 2 * ih) * 2 / 3 + hrest + iv; + break; + case 1: // top-right-hor + tnx += (nw - 2 * iv) / 3 + (wrest ? 1 : 0) + iv; + tnw = (nw - 2 * iv) * 2 / 3 + (wrest > 1 ? 1 : 0) + iv; + tnh = (nh - 2 * ih) / 3 + (hrest ? 1 : 0); + break; + case 2: // center + tnx += (nw - 2 * iv) / 3 + (wrest ? 1 : 0) + iv; + tnw = (nw - 2 * iv) / 3 + (wrest > 1 ? 1 : 0); + tny += (nh - 2 * ih) / 3 + (hrest ? 1 : 0) + ih; + tnh = (nh - 2 * ih) / 3 + (hrest > 1 ? 1 : 0); + break; + case 3: // bottom-right-vert + tnx += (nw - 2 * iv) * 2 / 3 + wrest + 2 * iv; + tnw = (nw - 2 * iv) / 3; + tny += (nh - 2 * ih) / 3 + (hrest ? 1 : 0) + ih; + tnh = (nh - 2 * ih) * 2 / 3 + hrest + iv; + break; + case 4: // (oldest) bottom-left-hor + tnw = (nw - 2 * iv) * 2 / 3 + wrest + iv; + tny += (nh - 2 * ih) * 2 / 3 + hrest + 2 * iv; + tnh = (nh - 2 * ih) / 3; + break; + } + + } + + resize(c, tnx, tny, tnw - 2 * c->bw, tnh - 2 * c->bw, False); + ++i; + } + } +} + +static void +flextile(Monitor *m) +{ + unsigned int n; + int oh = 0, ov = 0, ih = 0, iv = 0; // gaps outer/inner horizontal/vertical + + #if VANITYGAPS_PATCH + getgaps(m, &oh, &ov, &ih, &iv, &n); + #else + Client *c; + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + #endif // VANITYGAPS_PATCH + + if (m->lt[m->sellt]->preset.layout != m->ltaxis[LAYOUT] || + m->lt[m->sellt]->preset.masteraxis != m->ltaxis[MASTER] || + m->lt[m->sellt]->preset.stack1axis != m->ltaxis[STACK] || + m->lt[m->sellt]->preset.stack2axis != m->ltaxis[STACK2]) + setflexsymbols(m, n); + else if (m->lt[m->sellt]->preset.symbolfunc != NULL) + m->lt[m->sellt]->preset.symbolfunc(m, n); + + if (n == 0) + return; + + #if VANITYGAPS_PATCH && !VANITYGAPS_MONOCLE_PATCH + /* No outer gap if full screen monocle */ + if (abs(m->ltaxis[MASTER]) == MONOCLE && (abs(m->ltaxis[LAYOUT]) == NO_SPLIT || n <= m->nmaster)) { + oh = 0; + ov = 0; + } + #endif // VANITYGAPS_PATCH && !VANITYGAPS_MONOCLE_PATCH + + (&flexlayouts[abs(m->ltaxis[LAYOUT])])->arrange(m, m->wx + ov, m->wy + oh, m->wh - 2*oh, m->ww - 2*ov, ih, iv, n); + return; +} + +static void +setflexsymbols(Monitor *m, unsigned int n) +{ + int l; + char sym1, sym2, sym3; + Client *c; + + if (n == 0) + for (c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + + l = abs(m->ltaxis[LAYOUT]); + if (m->ltaxis[MASTER] == MONOCLE && (l == NO_SPLIT || !m->nmaster || n <= m->nmaster)) { + monoclesymbols(m, n); + return; + } + + if (m->ltaxis[STACK] == MONOCLE && (l == SPLIT_VERTICAL || l == SPLIT_HORIZONTAL_FIXED)) { + decksymbols(m, n); + return; + } + + /* Layout symbols */ + if (l == NO_SPLIT || !m->nmaster) { + sym1 = sym2 = sym3 = (int)tilesymb[m->ltaxis[MASTER]]; + } else { + sym2 = layoutsymb[l]; + if (m->ltaxis[LAYOUT] < 0) { + sym1 = tilesymb[m->ltaxis[STACK]]; + sym3 = tilesymb[m->ltaxis[MASTER]]; + } else { + sym1 = tilesymb[m->ltaxis[MASTER]]; + sym3 = tilesymb[m->ltaxis[STACK]]; + } + } + + snprintf(m->ltsymbol, sizeof m->ltsymbol, "%c%c%c", sym1, sym2, sym3); +} + +static void +monoclesymbols(Monitor *m, unsigned int n) +{ + if (n > 0) + snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n); + else + snprintf(m->ltsymbol, sizeof m->ltsymbol, "[M]"); +} + +static void +decksymbols(Monitor *m, unsigned int n) +{ + if (n > m->nmaster) + snprintf(m->ltsymbol, sizeof m->ltsymbol, "[]%d", n); + else + snprintf(m->ltsymbol, sizeof m->ltsymbol, "[D]"); +} + +/* Mirror layout axis for flextile */ +void +mirrorlayout(const Arg *arg) +{ + if (!selmon->lt[selmon->sellt]->arrange) + return; + selmon->ltaxis[LAYOUT] *= -1; + #if PERTAG_PATCH + selmon->pertag->ltaxis[selmon->pertag->curtag][0] = selmon->ltaxis[LAYOUT]; + #endif // PERTAG_PATCH + arrange(selmon); +} + +/* Rotate layout axis for flextile */ +void +rotatelayoutaxis(const Arg *arg) +{ + int incr = (arg->i > 0 ? 1 : -1); + int axis = abs(arg->i) - 1; + + if (!selmon->lt[selmon->sellt]->arrange) + return; + if (axis == LAYOUT) { + if (selmon->ltaxis[LAYOUT] >= 0) { + selmon->ltaxis[LAYOUT] += incr; + if (selmon->ltaxis[LAYOUT] >= LAYOUT_LAST) + selmon->ltaxis[LAYOUT] = 0; + else if (selmon->ltaxis[LAYOUT] < 0) + selmon->ltaxis[LAYOUT] = LAYOUT_LAST - 1; + } else { + selmon->ltaxis[LAYOUT] -= incr; + if (selmon->ltaxis[LAYOUT] <= -LAYOUT_LAST) + selmon->ltaxis[LAYOUT] = 0; + else if (selmon->ltaxis[LAYOUT] > 0) + selmon->ltaxis[LAYOUT] = -LAYOUT_LAST + 1; + } + } else { + selmon->ltaxis[axis] += incr; + if (selmon->ltaxis[axis] >= AXIS_LAST) + selmon->ltaxis[axis] = 0; + else if (selmon->ltaxis[axis] < 0) + selmon->ltaxis[axis] = AXIS_LAST - 1; + } + #if PERTAG_PATCH + selmon->pertag->ltaxis[selmon->pertag->curtag][axis] = selmon->ltaxis[axis]; + #endif // PERTAG_PATCH + arrange(selmon); + setflexsymbols(selmon, 0); +} + +void +incnstack(const Arg *arg) +{ + #if PERTAG_PATCH + selmon->nstack = selmon->pertag->nstacks[selmon->pertag->curtag] = MAX(selmon->nstack + arg->i, 0); + #else + selmon->nstack = MAX(selmon->nstack + arg->i, 0); + #endif // PERTAG_PATCH + arrange(selmon); +} diff --git a/suckless/dwm/patch/layout_flextile-deluxe.h b/suckless/dwm/patch/layout_flextile-deluxe.h new file mode 100644 index 00000000..9ec7324c --- /dev/null +++ b/suckless/dwm/patch/layout_flextile-deluxe.h @@ -0,0 +1,120 @@ +static void flextile(Monitor *m); +static void getfactsforrange(Monitor *m, int an, int ai, int size, int *rest, float *fact); +static void mirrorlayout(const Arg *arg); +static void rotatelayoutaxis(const Arg *arg); +#if IPC_PATCH || DWMC_PATCH +static void setlayoutaxisex(const Arg *arg); +#endif // IPC_PATCH | DWMC_PATCH +static void incnstack(const Arg *arg); + +/* Symbol handlers */ +static void setflexsymbols(Monitor *m, unsigned int n); +static void monoclesymbols(Monitor *m, unsigned int n); +static void decksymbols(Monitor *m, unsigned int n); + +/* Layout split */ +static void layout_no_split(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n); +static void layout_split_vertical(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n); +static void layout_split_horizontal(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n); +static void layout_split_vertical_dual_stack(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n); +static void layout_split_horizontal_dual_stack(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n); +static void layout_split_centered_vertical(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n); +static void layout_split_centered_horizontal(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n); +static void layout_floating_master(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n); +static void layout_split_vertical_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n); +static void layout_split_horizontal_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n); +static void layout_split_vertical_dual_stack_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n); +static void layout_split_horizontal_dual_stack_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n); +static void layout_split_centered_vertical_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n); +static void layout_split_centered_horizontal_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n); +static void layout_floating_master_fixed(Monitor *m, int x, int y, int h, int w, int ih, int iv, int n); + +/* Layout tile arrangements */ +static void arrange_left_to_right(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai); +static void arrange_top_to_bottom(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai); +static void arrange_monocle(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai); +static void arrange_gapplessgrid(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai); +static void arrange_gapplessgrid_alt1(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai); +static void arrange_gapplessgrid_alt2(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai); +static void arrange_gridmode(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai); +static void arrange_horizgrid(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai); +static void arrange_dwindle(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai); +static void arrange_spiral(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai); +static void arrange_tatami(Monitor *m, int ax, int ay, int ah, int aw, int ih, int iv, int n, int an, int ai); + +/* Named flextile constants */ +enum { + LAYOUT, // controls overall layout arrangement / split + MASTER, // indicates the tile arrangement for the master area + STACK, // indicates the tile arrangement for the stack area + STACK2, // indicates the tile arrangement for the secondary stack area + LTAXIS_LAST, +}; + +/* Layout arrangements */ +enum { + NO_SPLIT, + SPLIT_VERTICAL, // master stack vertical split + SPLIT_HORIZONTAL, // master stack horizontal split + SPLIT_CENTERED_VERTICAL, // centered master vertical split + SPLIT_CENTERED_HORIZONTAL, // centered master horizontal split + SPLIT_VERTICAL_DUAL_STACK, // master stack vertical split with dual stack + SPLIT_HORIZONTAL_DUAL_STACK, // master stack vertical split with dual stack + FLOATING_MASTER, // (fake) floating master + SPLIT_VERTICAL_FIXED, // master stack vertical fixed split + SPLIT_HORIZONTAL_FIXED, // master stack horizontal fixed split + SPLIT_CENTERED_VERTICAL_FIXED, // centered master vertical fixed split + SPLIT_CENTERED_HORIZONTAL_FIXED, // centered master horizontal fixed split + SPLIT_VERTICAL_DUAL_STACK_FIXED, // master stack vertical split with fixed dual stack + SPLIT_HORIZONTAL_DUAL_STACK_FIXED, // master stack vertical split with fixed dual stack + FLOATING_MASTER_FIXED, // (fake) fixed floating master + LAYOUT_LAST, +}; + +static char layoutsymb[] = { + 32, // " ", + 124, // "|", + 61, // "=", + 94, // "^", + 126, // "~", + 58, // ":", + 59, // ";", + 43, // "+", + 124, // "¦", + 61, // "=", + 94, // "^", + 126, // "~", + 58, // ":", + 59, // ";", + 43, // "+", +}; + +/* Tile arrangements */ +enum { + TOP_TO_BOTTOM, // clients are arranged vertically + LEFT_TO_RIGHT, // clients are arranged horizontally + MONOCLE, // clients are arranged in deck / monocle mode + GAPPLESSGRID, // clients are arranged in a gappless grid (original formula) + GAPPLESSGRID_ALT1, // clients are arranged in a gappless grid (alt. 1, fills rows first) + GAPPLESSGRID_ALT2, // clients are arranged in a gappless grid (alt. 2, fills columns first) + GRIDMODE, // clients are arranged in a grid + HORIZGRID, // clients are arranged in a horizontal grid + DWINDLE, // clients are arranged in fibonacci dwindle mode + SPIRAL, // clients are arranged in fibonacci spiral mode + TATAMI, // clients are arranged as tatami mats + AXIS_LAST, +}; + +static char tilesymb[] = { + 61, // "=", + 124, // "|", + 68, // "D", + 71, // "G", + 49, // "1", + 50, // "2" + 35, // "#", + 126, // "~", + 92, // "\\", + 64, // "@", + 84, // "T", +}; diff --git a/suckless/dwm/patch/layout_gapplessgrid.c b/suckless/dwm/patch/layout_gapplessgrid.c new file mode 100644 index 00000000..0330181e --- /dev/null +++ b/suckless/dwm/patch/layout_gapplessgrid.c @@ -0,0 +1,98 @@ +#if VANITYGAPS_PATCH +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++; + } + } +} +#else +void +gaplessgrid(Monitor *m) +{ + unsigned int i, n; + int x, y, cols, rows, ch, cw, cn, rn, rrest, crest; // counters + Client *c; + + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), 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 / rows; + cw = m->ww / cols; + rrest = m->wh - ch * rows; + crest = m->ww - cw * cols; + x = m->wx; + y = m->wy; + + 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 / rows; + rrest = m->wh - ch * rows; + } + resize(c, + x, + y + rn*ch + 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 + (cn < crest ? 1 : 0); + cn++; + } + } +} +#endif diff --git a/suckless/dwm/patch/layout_gapplessgrid.h b/suckless/dwm/patch/layout_gapplessgrid.h new file mode 100644 index 00000000..28a7b5d4 --- /dev/null +++ b/suckless/dwm/patch/layout_gapplessgrid.h @@ -0,0 +1 @@ +static void gaplessgrid(Monitor *m); \ No newline at end of file diff --git a/suckless/dwm/patch/layout_grid.c b/suckless/dwm/patch/layout_grid.c new file mode 100644 index 00000000..df198963 --- /dev/null +++ b/suckless/dwm/patch/layout_grid.c @@ -0,0 +1,60 @@ +#if VANITYGAPS_PATCH +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); + } +} +#else +void +grid(Monitor *m) +{ + unsigned int i, n; + int cx, cy, cw, ch, cc, cr, chrest, cwrest, cols, rows; + Client *c; + + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), 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 / (rows ? rows : 1); + cw = m->ww / (cols ? cols : 1); + chrest = m->wh - ch * rows; + cwrest = m->ww - cw * cols; + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { + cc = i / rows; + cr = i % rows; + cx = m->wx + cc * cw + MIN(cc, cwrest); + cy = m->wy + cr * ch + MIN(cr, chrest); + resize(c, cx, cy, cw + (cc < cwrest ? 1 : 0) - 2*c->bw, ch + (cr < chrest ? 1 : 0) - 2*c->bw, False); + } +} +#endif \ No newline at end of file diff --git a/suckless/dwm/patch/layout_grid.h b/suckless/dwm/patch/layout_grid.h new file mode 100644 index 00000000..81149ce5 --- /dev/null +++ b/suckless/dwm/patch/layout_grid.h @@ -0,0 +1 @@ +static void grid(Monitor *m); \ No newline at end of file diff --git a/suckless/dwm/patch/layout_horizgrid.c b/suckless/dwm/patch/layout_horizgrid.c new file mode 100644 index 00000000..48f66abe --- /dev/null +++ b/suckless/dwm/patch/layout_horizgrid.c @@ -0,0 +1,103 @@ +void +horizgrid(Monitor *m) { + Client *c; + unsigned int n, i; + int mx = 0, my = 0, mh = 0, mw = 0; + int sx = 0, sy = 0, sh = 0, sw = 0; + int ntop; + float mfacts = 0, sfacts = 0; + int mrest, srest, mtotal = 0, stotal = 0; + + #if VANITYGAPS_PATCH + int oh, ov, ih, iv; + getgaps(m, &oh, &ov, &ih, &iv, &n); + #else + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + #endif // VANITYGAPS_PATCH + if (n == 0) + return; + + if (n <= 2) + ntop = n; + else { + ntop = n / 2; + } + + #if VANITYGAPS_PATCH + 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 * (n - ntop - 1); + } + #else + sx = mx = m->wx; + sy = my = m->wy; + sh = mh = m->wh; + sw = mw = m->ww; + + if (n > ntop) { + sh = mh / 2; + mh = mh - sh; + sy = my + mh; + } + #endif // VANITYGAPS_PATCH + + /* calculate facts */ + #if CFACTS_PATCH + 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); + #else + mfacts = ntop; + sfacts = n - ntop; + + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < ntop) + mtotal += mh / mfacts; + else + stotal += sw / sfacts; + #endif // CFACTS_PATCH + + mrest = mh - mtotal; + srest = sw - stotal; + + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < ntop) { + #if CFACTS_PATCH + resize(c, mx, my, mw * (c->cfact / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); + #else + resize(c, mx, my, mw / mfacts + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); + #endif // CFACTS_PATCH + #if VANITYGAPS_PATCH + mx += WIDTH(c) + iv; + #else + mx += WIDTH(c); + #endif // VANITYGAPS_PATCH + } else { + #if CFACTS_PATCH + resize(c, sx, sy, sw * (c->cfact / sfacts) + ((i - ntop) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0); + #else + resize(c, sx, sy, sw / sfacts + ((i - ntop) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0); + #endif // CFACTS_PATCH + #if VANITYGAPS_PATCH + sx += WIDTH(c) + iv; + #else + sx += WIDTH(c); + #endif // VANITYGAPS_PATCH + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/layout_horizgrid.h b/suckless/dwm/patch/layout_horizgrid.h new file mode 100644 index 00000000..71a57fbb --- /dev/null +++ b/suckless/dwm/patch/layout_horizgrid.h @@ -0,0 +1 @@ +static void horizgrid(Monitor *m); \ No newline at end of file diff --git a/suckless/dwm/patch/layout_monocle.c b/suckless/dwm/patch/layout_monocle.c new file mode 100644 index 00000000..1533aa97 --- /dev/null +++ b/suckless/dwm/patch/layout_monocle.c @@ -0,0 +1,37 @@ +#if VANITYGAPS_PATCH && VANITYGAPS_MONOCLE_PATCH +void +monocle(Monitor *m) +{ + unsigned int n; + int oh, ov, ih, iv; + Client *c; + + getgaps(m, &oh, &ov, &ih, &iv, &n); + + #if !MONOCLESYMBOL_PATCH + if (n > 0) /* override layout symbol */ + snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n); + #endif // MONOCLESYMBOL_PATCH + 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); +} +#else +void +monocle(Monitor *m) +{ + #if !MONOCLESYMBOL_PATCH + unsigned int n = 0; + #endif // MONOCLESYMBOL_PATCH + Client *c; + + #if !MONOCLESYMBOL_PATCH + 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); + #endif // MONOCLESYMBOL_PATCH + 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); +} +#endif // VANITYGAPS_PATCH \ No newline at end of file diff --git a/suckless/dwm/patch/layout_monocle.h b/suckless/dwm/patch/layout_monocle.h new file mode 100644 index 00000000..d3df9604 --- /dev/null +++ b/suckless/dwm/patch/layout_monocle.h @@ -0,0 +1 @@ +static void monocle(Monitor *m); \ No newline at end of file diff --git a/suckless/dwm/patch/layout_nrowgrid.c b/suckless/dwm/patch/layout_nrowgrid.c new file mode 100644 index 00000000..5709d806 --- /dev/null +++ b/suckless/dwm/patch/layout_nrowgrid.c @@ -0,0 +1,103 @@ +#if VANITYGAPS_PATCH +void +nrowgrid(Monitor *m) +{ + unsigned int n = 0, i = 0, 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), i++, 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); + } +} +#else +void +nrowgrid(Monitor *m) +{ + unsigned int n = 0, i = 0, ri = 0, ci = 0; /* counters */ + 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; + + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + 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; + ch = m->wh / rows; + uh = ch; + + for (c = nexttiled(m->clients); c; c = nexttiled(c->next), i++, ci++) { + if (ci == cols) { + uw = 0; + ci = 0; + ri++; + + /* next row */ + cols = (n - uc) / (rows - ri); + uc += cols; + cy = m->wy + uh; + uh += ch; + } + + cx = m->wx + uw; + cw = (m->ww - uw) / (cols - ci); + uw += cw; + + resize(c, cx, cy, cw - (2*c->bw), ch - (2*c->bw), 0); + } +} +#endif \ No newline at end of file diff --git a/suckless/dwm/patch/layout_nrowgrid.h b/suckless/dwm/patch/layout_nrowgrid.h new file mode 100644 index 00000000..de71a504 --- /dev/null +++ b/suckless/dwm/patch/layout_nrowgrid.h @@ -0,0 +1 @@ +static void nrowgrid(Monitor *m); \ No newline at end of file diff --git a/suckless/dwm/patch/layout_tile.c b/suckless/dwm/patch/layout_tile.c new file mode 100644 index 00000000..fa0b90a4 --- /dev/null +++ b/suckless/dwm/patch/layout_tile.c @@ -0,0 +1,73 @@ +static void +tile(Monitor *m) +{ + unsigned int i, n; + 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; + + + #if VANITYGAPS_PATCH + int oh, ov, ih, iv; + getgaps(m, &oh, &ov, &ih, &iv, &n); + #else + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + #endif // VANITYGAPS_PATCH + + if (n == 0) + return; + + #if VANITYGAPS_PATCH + 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) * m->mfact; + sx = mx + mw + iv; + } + #else + sx = mx = m->wx; + sy = my = m->wy; + sh = mh = m->wh; + sw = mw = m->ww; + + if (m->nmaster && n > m->nmaster) { + sw = mw * (1 - m->mfact); + mw = mw * m->mfact; + sx = mx + mw; + } + #endif // VANITYGAPS_PATCH + + 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) { + #if CFACTS_PATCH + resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) * c->cfact + (i < mrest ? 1 : 0) - (2*c->bw), 0); + #else + resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0); + #endif // CFACTS_PATCH + #if VANITYGAPS_PATCH + my += HEIGHT(c) + ih; + #else + my += HEIGHT(c); + #endif + } else { + #if CFACTS_PATCH + resize(c, sx, sy, sw - (2*c->bw), (sh / sfacts) * c->cfact + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0); + #else + resize(c, sx, sy, sw - (2*c->bw), (sh / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0); + #endif // CFACTS_PATCH + #if VANITYGAPS_PATCH + sy += HEIGHT(c) + ih; + #else + sy += HEIGHT(c); + #endif + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/layout_tile.h b/suckless/dwm/patch/layout_tile.h new file mode 100644 index 00000000..8730e132 --- /dev/null +++ b/suckless/dwm/patch/layout_tile.h @@ -0,0 +1 @@ +static void tile(Monitor *); \ No newline at end of file diff --git a/suckless/dwm/patch/layoutmenu.sh b/suckless/dwm/patch/layoutmenu.sh new file mode 100755 index 00000000..0bb04565 --- /dev/null +++ b/suckless/dwm/patch/layoutmenu.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +cat <<> Floating Layout 1 +[M] Monocle Layout 2 +EOF + diff --git a/suckless/dwm/patch/maximize.c b/suckless/dwm/patch/maximize.c new file mode 100644 index 00000000..53336eba --- /dev/null +++ b/suckless/dwm/patch/maximize.c @@ -0,0 +1,69 @@ +void +maximize(int x, int y, int w, int h) +{ + XEvent ev; + + if (!selmon->sel || selmon->sel->isfixed) + return; + XRaiseWindow(dpy, selmon->sel->win); + if (!selmon->sel->ismax) { + if (!selmon->lt[selmon->sellt]->arrange || selmon->sel->isfloating) + selmon->sel->wasfloating = True; + else { + togglefloating(NULL); + selmon->sel->wasfloating = False; + } + selmon->sel->oldx = selmon->sel->x; + selmon->sel->oldy = selmon->sel->y; + selmon->sel->oldw = selmon->sel->w; + selmon->sel->oldh = selmon->sel->h; + resize(selmon->sel, x, y, w, h, True); + selmon->sel->ismax = True; + } + else { + resize(selmon->sel, selmon->sel->oldx, selmon->sel->oldy, selmon->sel->oldw, selmon->sel->oldh, True); + if (!selmon->sel->wasfloating) + togglefloating(NULL); + selmon->sel->ismax = False; + } + drawbar(selmon); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); +} + +#if SETBORDERPX_PATCH +void +togglemax(const Arg *arg) +{ + maximize(selmon->wx, selmon->wy, selmon->ww - 2 * selmon->borderpx, selmon->wh - 2 * selmon->borderpx); +} + +void +toggleverticalmax(const Arg *arg) +{ + maximize(selmon->sel->x, selmon->wy, selmon->sel->w, selmon->wh - 2 * selmon->borderpx); +} + +void +togglehorizontalmax(const Arg *arg) +{ + maximize(selmon->wx, selmon->sel->y, selmon->ww - 2 * selmon->borderpx, selmon->sel->h); +} +#else +void +togglemax(const Arg *arg) +{ + maximize(selmon->wx, selmon->wy, selmon->ww - 2 * borderpx, selmon->wh - 2 * borderpx); +} + +void +toggleverticalmax(const Arg *arg) +{ + maximize(selmon->sel->x, selmon->wy, selmon->sel->w, selmon->wh - 2 * borderpx); +} + +void +togglehorizontalmax(const Arg *arg) +{ + maximize(selmon->wx, selmon->sel->y, selmon->ww - 2 * borderpx, selmon->sel->h); +} +#endif // SETBORDERPX_PATCH \ No newline at end of file diff --git a/suckless/dwm/patch/maximize.h b/suckless/dwm/patch/maximize.h new file mode 100644 index 00000000..e06a3ffe --- /dev/null +++ b/suckless/dwm/patch/maximize.h @@ -0,0 +1,4 @@ +static void maximize(int x, int y, int w, int h); +static void togglemax(const Arg *arg); +static void toggleverticalmax(const Arg *arg); +static void togglehorizontalmax(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/moveplace.c b/suckless/dwm/patch/moveplace.c new file mode 100644 index 00000000..cfd17a47 --- /dev/null +++ b/suckless/dwm/patch/moveplace.c @@ -0,0 +1,29 @@ +void +moveplace(const Arg *arg) +{ + Client *c; + int nh, nw, nx, ny; + c = selmon->sel; + if (!c || (arg->ui >= 9)) + return; + if (selmon->lt[selmon->sellt]->arrange && !c->isfloating) + togglefloating(NULL); + nh = (selmon->wh / 3) - (c->bw * 2); + nw = (selmon->ww / 3) - (c->bw * 2); + 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 - nw - c->bw*2; + else + nx = selmon->wx + selmon->ww/2 - nw/2 - c->bw; + if (ny <0) + ny = selmon->wy; + else if (ny > 0) + ny = selmon->wy + selmon->wh - nh - c->bw*2; + else + ny = selmon->wy + selmon->wh/2 - nh/2 - c->bw; + resize(c, nx, ny, nw, nh, True); + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, nw/2, nh/2); +} \ No newline at end of file diff --git a/suckless/dwm/patch/moveplace.h b/suckless/dwm/patch/moveplace.h new file mode 100644 index 00000000..f921b8e3 --- /dev/null +++ b/suckless/dwm/patch/moveplace.h @@ -0,0 +1,3 @@ +enum { WIN_NW, WIN_N, WIN_NE, WIN_W, WIN_C, WIN_E, WIN_SW, WIN_S, WIN_SE }; + +static void moveplace(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/moveresize.c b/suckless/dwm/patch/moveresize.c new file mode 100644 index 00000000..35f0a2f0 --- /dev/null +++ b/suckless/dwm/patch/moveresize.c @@ -0,0 +1,64 @@ +void +moveresize(const Arg *arg) { + /* only floating windows can be moved */ + Client *c; + c = selmon->sel; + int x, y, w, h, nx, ny, nw, nh, ox, oy, ow, oh; + char xAbs, yAbs, wAbs, hAbs; + int msx, msy, dx, dy, nmx, nmy; + unsigned int dui; + Window dummy; + + if (!c || !arg) + return; + if (selmon->lt[selmon->sellt]->arrange && !c->isfloating) + return; + if (sscanf((char *)arg->v, "%d%c %d%c %d%c %d%c", &x, &xAbs, &y, &yAbs, &w, &wAbs, &h, &hAbs) != 8) + return; + + /* compute new window position; prevent window from be positioned outside the current monitor */ + nw = c->w + w; + if (wAbs == 'W') + nw = w < selmon->mw - 2 * c->bw ? w : selmon->mw - 2 * c->bw; + + nh = c->h + h; + if (hAbs == 'H') + nh = h < selmon->mh - 2 * c->bw ? h : selmon->mh - 2 * c->bw; + + nx = c->x + x; + if (xAbs == 'X') { + if (x < selmon->mx) + nx = selmon->mx; + else if (x > selmon->mx + selmon->mw) + nx = selmon->mx + selmon->mw - nw - 2 * c->bw; + else + nx = x; + } + + ny = c->y + y; + if (yAbs == 'Y') { + if (y < selmon->my) + ny = selmon->my; + else if (y > selmon->my + selmon->mh) + ny = selmon->my + selmon->mh - nh - 2 * c->bw; + else + ny = y; + } + + ox = c->x; + oy = c->y; + ow = c->w; + oh = c->h; + + XRaiseWindow(dpy, c->win); + Bool xqp = XQueryPointer(dpy, root, &dummy, &dummy, &msx, &msy, &dx, &dy, &dui); + resize(c, nx, ny, nw, nh, True); + + /* move cursor along with the window to avoid problems caused by the sloppy focus */ + if (xqp && ox <= msx && (ox + ow) >= msx && oy <= msy && (oy + oh) >= msy) + { + nmx = c->x - ox + c->w - ow; + nmy = c->y - oy + c->h - oh; + XWarpPointer(dpy, None, None, 0, 0, 0, 0, nmx, nmy); + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/moveresize.h b/suckless/dwm/patch/moveresize.h new file mode 100644 index 00000000..5d963ff8 --- /dev/null +++ b/suckless/dwm/patch/moveresize.h @@ -0,0 +1 @@ +static void moveresize(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/movestack.c b/suckless/dwm/patch/movestack.c similarity index 50% rename from suckless/dwm/movestack.c rename to suckless/dwm/patch/movestack.c index c0404624..ab97b18c 100644 --- a/suckless/dwm/movestack.c +++ b/suckless/dwm/patch/movestack.c @@ -1,49 +1,50 @@ void -movestack(const Arg *arg) { +movestack(const Arg *arg) +{ Client *c = NULL, *p = NULL, *pc = NULL, *i; - - if(arg->i > 0) { + if (arg->i > 0) { + if (!selmon->sel) + return; /* find the client after selmon->sel */ - for(c = selmon->sel->next; c && (!ISVISIBLE(c) || c->isfloating); c = c->next); - if(!c) - for(c = selmon->clients; c && (!ISVISIBLE(c) || c->isfloating); c = c->next); - + for (c = selmon->sel->next; c && (!ISVISIBLE(c) || c->isfloating); c = c->next); + if (!c) + for (c = selmon->clients; c && (!ISVISIBLE(c) || c->isfloating); c = c->next); } else { /* find the client before selmon->sel */ - for(i = selmon->clients; i != selmon->sel; i = i->next) + for (i = selmon->clients; i != selmon->sel; i = i->next) if(ISVISIBLE(i) && !i->isfloating) c = i; - if(!c) - for(; i; i = i->next) - if(ISVISIBLE(i) && !i->isfloating) + if (!c) + for (; i; i = i->next) + if (ISVISIBLE(i) && !i->isfloating) c = i; } + /* find the client before selmon->sel and c */ - for(i = selmon->clients; i && (!p || !pc); i = i->next) { - if(i->next == selmon->sel) + for (i = selmon->clients; i && (!p || !pc); i = i->next) { + if (i->next == selmon->sel) p = i; - if(i->next == c) + if (i->next == c) pc = i; } /* swap c and selmon->sel selmon->clients in the selmon->clients list */ - if(c && c != selmon->sel) { + if (c && c != selmon->sel) { Client *temp = selmon->sel->next==c?selmon->sel:selmon->sel->next; selmon->sel->next = c->next==selmon->sel?c:c->next; c->next = temp; - if(p && p != c) + if (p && p != c) p->next = c; - if(pc && pc != selmon->sel) + if (pc && pc != selmon->sel) pc->next = selmon->sel; - if(selmon->sel == selmon->clients) + if (selmon->sel == selmon->clients) selmon->clients = c; - else if(c == selmon->clients) + else if (c == selmon->clients) selmon->clients = selmon->sel; arrange(selmon); } -} - +} \ No newline at end of file diff --git a/suckless/dwm/patch/movestack.h b/suckless/dwm/patch/movestack.h new file mode 100644 index 00000000..19ac5d8a --- /dev/null +++ b/suckless/dwm/patch/movestack.h @@ -0,0 +1 @@ +static void movestack(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/mpdcontrol.c b/suckless/dwm/patch/mpdcontrol.c new file mode 100644 index 00000000..c7ff7862 --- /dev/null +++ b/suckless/dwm/patch/mpdcontrol.c @@ -0,0 +1,144 @@ +#include +#include +#include +#include + +#include + +#define MPDHOST "localhost" +#define MPDPORT 6600 + +struct mpd_connection *get_conn() +{ + struct mpd_connection *conn; + + conn = mpd_connection_new(MPDHOST, MPDPORT, 1000); + + if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS) { + fprintf(stderr, "Could not connect to mpd: %s\n", mpd_connection_get_error_message(conn)); + + mpd_connection_free(conn); + return NULL; + } + + return conn; +} + +void mpdchange(const Arg *direction) +{ + struct mpd_connection *conn; + + conn = get_conn(); + + if (conn == NULL) { + return; + } + + if (direction->i > 0) { + mpd_run_next(conn); + } + else { + mpd_run_previous(conn); + } + + mpd_connection_free(conn); +} + +char *get_regerror(int errcode, regex_t *compiled) +{ + size_t length = regerror(errcode, compiled, NULL, 0); + char *buffer = malloc(length); + (void) regerror(errcode, compiled, buffer, length); + + return buffer; +} + +void mpdcontrol() +{ + struct mpd_connection *conn; + struct mpd_status *status; + struct mpd_song *song; + enum mpd_state state; + + const char *filename; + + regex_t expr; + + conn = get_conn(); + + if (conn == NULL) { + return; + } + + status = mpd_run_status(conn); + + if (status == NULL) { + fprintf(stderr, "Could not get mpd status: %s\n", mpd_status_get_error(status)); + + mpd_status_free(status); + mpd_connection_free(conn); + return; + } + + state = mpd_status_get_state(status); + + if (state == MPD_STATE_STOP || state == MPD_STATE_PAUSE) { + mpd_run_play(conn); + mpd_status_free(status); + mpd_connection_free(conn); + } + else if (state != MPD_STATE_UNKNOWN) { //playing some music + song = mpd_run_current_song(conn); + + if (song == NULL){ + fprintf(stderr, "Error fetching current song!\n"); + + mpd_song_free(song); + mpd_status_free(status); + mpd_connection_free(conn); + return; + } + + filename = mpd_song_get_uri(song); + + int errcode = regcomp(&expr, "^[[:alnum:]]+://", REG_EXTENDED|REG_NOSUB); + if (errcode != 0) { + char *err = get_regerror(errcode, &expr); + fprintf(stderr, "Could not compile regexp: %s\n", err); + + mpd_song_free(song); + mpd_status_free(status); + mpd_connection_free(conn); + free(err); + regfree(&expr); + return; + } + + int matchcode = regexec(&expr, filename, 0, NULL, 0); + + if (matchcode == 0) { + if (strstr(filename, "file://") == filename) { //match just at the start of the filename + //this means that mpd is playing a file outside the music_dir, + //but on disk, so we can safely pause + mpd_run_toggle_pause(conn); + } + else { + mpd_run_stop(conn); + } + } + else if (matchcode == REG_NOMATCH) { + mpd_run_toggle_pause(conn); + } + else { + char *err = get_regerror(matchcode, &expr); + fprintf(stderr, "Error while matching regexp: %s\n", err); + + free(err); + } + + regfree(&expr); + mpd_song_free(song); + mpd_status_free(status); + mpd_connection_free(conn); + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/mpdcontrol.h b/suckless/dwm/patch/mpdcontrol.h new file mode 100644 index 00000000..b8825d4f --- /dev/null +++ b/suckless/dwm/patch/mpdcontrol.h @@ -0,0 +1,2 @@ +static void mpdchange(const Arg *direction); +static void mpdcontrol(); \ No newline at end of file diff --git a/suckless/dwm/patch/nomodbuttons.c b/suckless/dwm/patch/nomodbuttons.c new file mode 100644 index 00000000..c4e082ec --- /dev/null +++ b/suckless/dwm/patch/nomodbuttons.c @@ -0,0 +1,7 @@ +void +togglenomodbuttons(const Arg *arg) +{ + nomodbuttons = !nomodbuttons; + if (selmon->sel) + grabbuttons(selmon->sel, 1); +} \ No newline at end of file diff --git a/suckless/dwm/patch/nomodbuttons.h b/suckless/dwm/patch/nomodbuttons.h new file mode 100644 index 00000000..4e6c572b --- /dev/null +++ b/suckless/dwm/patch/nomodbuttons.h @@ -0,0 +1 @@ +static void togglenomodbuttons(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/pertag.c b/suckless/dwm/patch/pertag.c new file mode 100644 index 00000000..3ca7ab2a --- /dev/null +++ b/suckless/dwm/patch/pertag.c @@ -0,0 +1,69 @@ +struct Pertag { + unsigned int curtag, prevtag; /* current and previous tag */ + int nmasters[NUMTAGS + 1]; /* number of windows in master area */ + #if FLEXTILE_DELUXE_LAYOUT + int nstacks[NUMTAGS + 1]; /* number of windows in primary stack area */ + int ltaxis[NUMTAGS + 1][LTAXIS_LAST]; + const Layout *ltidxs[NUMTAGS + 1][3]; /* matrix of tags and layouts indexes */ + #else + const Layout *ltidxs[NUMTAGS + 1][2]; /* matrix of tags and layouts indexes */ + #endif // FLEXTILE_DELUXE_LAYOUT + float mfacts[NUMTAGS + 1]; /* mfacts per tag */ + unsigned int sellts[NUMTAGS + 1]; /* selected layouts */ + #if PERTAGBAR_PATCH + int showbars[NUMTAGS + 1]; /* display bar for the current tag */ + #endif // PERTAGBAR_PATCH + #if SWAPFOCUS_PATCH + Client *prevclient[NUMTAGS + 1]; + #endif // SWAPFOCUS_PATCH + #if ZOOMSWAP_PATCH + Client *prevzooms[NUMTAGS + 1]; /* store zoom information */ + #endif // ZOOMSWAP_PATCH + #if VANITYGAPS_PATCH + int enablegaps[NUMTAGS + 1]; + #endif // VANITYGAPS_PATCH +}; + +void +pertagview(const Arg *arg) +{ + int i; + unsigned int tmptag; + if (arg->ui & TAGMASK) { + selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + #if SCRATCHPADS_PATCH + if (arg->ui == ~SPTAGMASK) + #else + if (arg->ui == ~0) + #endif // SCRATCHPADS_PATCH + 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]; + #if FLEXTILE_DELUXE_LAYOUT + selmon->nstack = selmon->pertag->nstacks[selmon->pertag->curtag]; + #endif // FLEXTILE_DELUXE_LAYOUT + 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 FLEXTILE_DELUXE_LAYOUT + selmon->ltaxis[LAYOUT] = selmon->pertag->ltaxis[selmon->pertag->curtag][LAYOUT]; + selmon->ltaxis[MASTER] = selmon->pertag->ltaxis[selmon->pertag->curtag][MASTER]; + selmon->ltaxis[STACK] = selmon->pertag->ltaxis[selmon->pertag->curtag][STACK]; + selmon->ltaxis[STACK2] = selmon->pertag->ltaxis[selmon->pertag->curtag][STACK2]; + #endif // FLEXTILE_DELUXE_LAYOUT + #if PERTAGBAR_PATCH + if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) + togglebar(NULL); + #endif // PERTAGBAR_PATCH +} \ No newline at end of file diff --git a/suckless/dwm/patch/pertag.h b/suckless/dwm/patch/pertag.h new file mode 100644 index 00000000..ac5288d3 --- /dev/null +++ b/suckless/dwm/patch/pertag.h @@ -0,0 +1 @@ +static void pertagview(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/placemouse.c b/suckless/dwm/patch/placemouse.c new file mode 100644 index 00000000..4f8fcc3f --- /dev/null +++ b/suckless/dwm/patch/placemouse.c @@ -0,0 +1,151 @@ +void +moveorplace(const Arg *arg) { + if ((!selmon->lt[selmon->sellt]->arrange || selmon->sel->isfloating)) + movemouse(arg); + else + placemouse(arg); +} + +void +placemouse(const Arg *arg) +{ + int x, y, px, py, ocx, ocy, nx = -9999, ny = -9999, freemove = 0; + Client *c, *r = NULL, *at, *prevr; + Monitor *m; + XEvent ev; + XWindowAttributes wa; + Time lasttime = 0; + int attachmode, prevattachmode; + attachmode = prevattachmode = -1; + + if (!(c = selmon->sel) || !c->mon->lt[c->mon->sellt]->arrange) /* no support for placemouse when floating layout is used */ + return; + if (c->isfullscreen) /* no support placing fullscreen windows by mouse */ + return; + restack(selmon); + prevr = c; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, + None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) + return; + + c->isfloating = 0; + c->beingmoved = 1; + + XGetWindowAttributes(dpy, c->win, &wa); + ocx = wa.x; + ocy = wa.y; + + if (arg->i == 2) // warp cursor to client center + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, WIDTH(c) / 2, HEIGHT(c) / 2); + + 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 ((ev.xmotion.time - lasttime) <= (1000 / 60)) + continue; + lasttime = ev.xmotion.time; + + nx = ocx + (ev.xmotion.x - x); + ny = ocy + (ev.xmotion.y - y); + + if (!freemove && (abs(nx - ocx) > snap || abs(ny - ocy) > snap)) + freemove = 1; + + if (freemove) + XMoveWindow(dpy, c->win, nx, ny); + + if ((m = recttomon(ev.xmotion.x, ev.xmotion.y, 1, 1)) && m != selmon) + selmon = m; + + if (arg->i == 1) { // tiled position is relative to the client window center point + px = nx + wa.width / 2; + py = ny + wa.height / 2; + } else { // tiled position is relative to the mouse cursor + px = ev.xmotion.x; + py = ev.xmotion.y; + } + + r = recttoclient(px, py, 1, 1); + + if (!r || r == c) + break; + + if ((((float)(r->y + r->h - py) / r->h) > ((float)(r->x + r->w - px) / r->w) + && (abs(r->y - py) < r->h / 2)) || (abs(r->x - px) < r->w / 2)) + attachmode = 1; // above + else + attachmode = 0; // below + + if ((r && r != prevr) || (attachmode != prevattachmode)) { + detachstack(c); + detach(c); + if (c->mon != r->mon) + arrangemon(c->mon); + + c->mon = r->mon; + r->mon->sel = r; + + if (attachmode) { + if (r == r->mon->clients) + attach(c); + else { + for (at = r->mon->clients; at->next != r; at = at->next); + c->next = at->next; + at->next = c; + } + } else { + c->next = r->next; + r->next = c; + } + + attachstack(c); + arrangemon(r->mon); + prevr = r; + prevattachmode = attachmode; + } + break; + } + } while (ev.type != ButtonRelease); + XUngrabPointer(dpy, CurrentTime); + + if ((m = recttomon(ev.xmotion.x, ev.xmotion.y, 1, 1)) && m != c->mon) { + detach(c); + detachstack(c); + arrangemon(c->mon); + c->mon = m; + attach(c); + attachstack(c); + selmon = m; + } + + focus(c); + c->beingmoved = 0; + + if (nx != -9999) + resize(c, nx, ny, c->w, c->h, 0); + arrangemon(c->mon); +} + +Client * +recttoclient(int x, int y, int w, int h) +{ + Client *c, *r = NULL; + int a, area = 0; + + for (c = nexttiled(selmon->clients); c; c = nexttiled(c->next)) { + if ((a = INTERSECTC(x, y, w, h, c)) > area) { + area = a; + r = c; + } + } + return r; +} \ No newline at end of file diff --git a/suckless/dwm/patch/placemouse.h b/suckless/dwm/patch/placemouse.h new file mode 100644 index 00000000..8687ae37 --- /dev/null +++ b/suckless/dwm/patch/placemouse.h @@ -0,0 +1,6 @@ +#define INTERSECTC(x,y,w,h,z) (MAX(0, MIN((x)+(w),(z)->x+(z)->w) - MAX((x),(z)->x)) \ + * MAX(0, MIN((y)+(h),(z)->y+(z)->h) - MAX((y),(z)->y))) + +static void moveorplace(const Arg *arg); +static void placemouse(const Arg *arg); +static Client *recttoclient(int x, int y, int w, int h); diff --git a/suckless/dwm/patch/push.c b/suckless/dwm/patch/push.c new file mode 100644 index 00000000..ae359289 --- /dev/null +++ b/suckless/dwm/patch/push.c @@ -0,0 +1,71 @@ +static Client * +nextc(Client *c, float f) +{ + if (!f) + return nexttiled(c); + + for (; c && !ISVISIBLE(c); c = c->next); + return c; +} + +static Client * +prevc(Client *c, float f) +{ + Client *p, *r; + + for (p = selmon->clients, r = NULL; c && p && p != c; p = p->next) + if ((f || !p->isfloating) && ISVISIBLE(p)) + r = p; + return r; +} + +static void +pushup(const Arg *arg) +{ + Client *sel = selmon->sel; + Client *c; + + if (!sel || (sel->isfloating && !arg->f)) + return; + if ((c = prevc(sel, arg->f))) { + /* attach before c */ + detach(sel); + sel->next = c; + if (selmon->clients == c) + selmon->clients = sel; + else { + for (c = selmon->clients; c->next != sel->next; c = c->next); + c->next = sel; + } + } else { + /* move to the end */ + for (c = sel; c->next; c = c->next); + detach(sel); + sel->next = NULL; + c->next = sel; + } + focus(sel); + arrange(selmon); +} + +static void +pushdown(const Arg *arg) +{ + Client *sel = selmon->sel; + Client *c; + + if (!sel || (sel->isfloating && !arg->f)) + return; + if ((c = nextc(sel->next, arg->f))) { + /* attach after c */ + detach(sel); + sel->next = c->next; + c->next = sel; + } else { + /* move to the front */ + detach(sel); + attach(sel); + } + focus(sel); + arrange(selmon); +} \ No newline at end of file diff --git a/suckless/dwm/patch/push.h b/suckless/dwm/patch/push.h new file mode 100644 index 00000000..9cad8b38 --- /dev/null +++ b/suckless/dwm/patch/push.h @@ -0,0 +1,4 @@ +static Client * nextc(Client *c, float f); +static Client * prevc(Client *c, float f); +static void pushup(const Arg *arg); +static void pushdown(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/push_no_master.c b/suckless/dwm/patch/push_no_master.c new file mode 100644 index 00000000..5ff9326b --- /dev/null +++ b/suckless/dwm/patch/push_no_master.c @@ -0,0 +1,43 @@ +Client * +prevt(Client *c) +{ + Client *p, *r; + + for (p = selmon->clients, r = NULL; p && p != c; p = p->next) + if (!p->isfloating && ISVISIBLE(p)) + r = p; + return r; +} + +void +pushup(const Arg *arg) +{ + Client *sel = selmon->sel, *c; + + if (!sel || sel->isfloating) + return; + if ((c = prevt(sel)) && c != nexttiled(selmon->clients)) { + detach(sel); + sel->next = c; + for (c = selmon->clients; c->next != sel->next; c = c->next); + c->next = sel; + } + focus(sel); + arrange(selmon); +} + +void +pushdown(const Arg *arg) +{ + Client *sel = selmon->sel, *c; + + if (!sel || sel->isfloating || sel == nexttiled(selmon->clients)) + return; + if ((c = nexttiled(sel->next))) { + detach(sel); + sel->next = c->next; + c->next = sel; + } + focus(sel); + arrange(selmon); +} \ No newline at end of file diff --git a/suckless/dwm/patch/push_no_master.h b/suckless/dwm/patch/push_no_master.h new file mode 100644 index 00000000..7ea061dc --- /dev/null +++ b/suckless/dwm/patch/push_no_master.h @@ -0,0 +1,3 @@ +Client * prevt(Client *c); +static void pushup(const Arg *arg); +static void pushdown(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/reorganizetags.c b/suckless/dwm/patch/reorganizetags.c new file mode 100644 index 00000000..da27ecd8 --- /dev/null +++ b/suckless/dwm/patch/reorganizetags.c @@ -0,0 +1,27 @@ +void +reorganizetags(const Arg *arg) +{ + Client *c; + unsigned int occ, unocc, i; + unsigned int tagdest[NUMTAGS]; + + occ = 0; + for (c = selmon->clients; c; c = c->next) + occ |= (1 << (ffs(c->tags)-1)); + unocc = 0; + for (i = 0; i < NUMTAGS; ++i) { + while (unocc < i && (occ & (1 << unocc))) + unocc++; + if (occ & (1 << i)) { + tagdest[i] = unocc; + occ &= ~(1 << i); + occ |= 1 << unocc; + } + } + + for (c = selmon->clients; c; c = c->next) + c->tags = 1 << tagdest[ffs(c->tags)-1]; + if (selmon->sel) + selmon->tagset[selmon->seltags] = selmon->sel->tags; + arrange(selmon); +} \ No newline at end of file diff --git a/suckless/dwm/patch/reorganizetags.h b/suckless/dwm/patch/reorganizetags.h new file mode 100644 index 00000000..27c0cea3 --- /dev/null +++ b/suckless/dwm/patch/reorganizetags.h @@ -0,0 +1 @@ +static void reorganizetags(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/restartsig.c b/suckless/dwm/patch/restartsig.c new file mode 100644 index 00000000..0bef576a --- /dev/null +++ b/suckless/dwm/patch/restartsig.c @@ -0,0 +1,15 @@ +static int restart = 0; + +void +sighup(int unused) +{ + Arg a = {.i = 1}; + quit(&a); +} + +void +sigterm(int unused) +{ + Arg a = {.i = 0}; + quit(&a); +} \ No newline at end of file diff --git a/suckless/dwm/patch/restartsig.h b/suckless/dwm/patch/restartsig.h new file mode 100644 index 00000000..5a08c393 --- /dev/null +++ b/suckless/dwm/patch/restartsig.h @@ -0,0 +1,2 @@ +static void sighup(int unused); +static void sigterm(int unused); \ No newline at end of file diff --git a/suckless/dwm/patch/riodraw.c b/suckless/dwm/patch/riodraw.c new file mode 100644 index 00000000..b80328fd --- /dev/null +++ b/suckless/dwm/patch/riodraw.c @@ -0,0 +1,103 @@ +/* drag out an area using slop and resize the selected window to it. */ +int +riodraw(Client *c, const char slopstyle[]) +{ + int i; + char str[100]; + char strout[100]; + char tmpstring[30] = {0}; + char slopcmd[100] = "slop -f x%xx%yx%wx%hx "; + int firstchar = 0; + int counter = 0; + + strcat(slopcmd, slopstyle); + FILE *fp = popen(slopcmd, "r"); + + while (fgets(str, 100, fp) != NULL) + strcat(strout, str); + + pclose(fp); + + if (strlen(strout) < 6) + return 0; + + for (i = 0; i < strlen(strout); i++){ + if (!firstchar) { + if (strout[i] == 'x') + firstchar = 1; + continue; + } + + if (strout[i] != 'x') + tmpstring[strlen(tmpstring)] = strout[i]; + else { + riodimensions[counter] = atoi(tmpstring); + counter++; + memset(tmpstring,0,strlen(tmpstring)); + } + } + + if (riodimensions[0] <= -40 || riodimensions[1] <= -40 || riodimensions[2] <= 50 || riodimensions[3] <= 50) { + riodimensions[3] = -1; + return 0; + } + + if (c) { + rioposition(c, riodimensions[0], riodimensions[1], riodimensions[2], riodimensions[3]); + return 0; + } + + return 1; +} + +void +rioposition(Client *c, int x, int y, int w, int h) +{ + Monitor *m; + if ((m = recttomon(x, y, w, h)) && m != c->mon) { + detach(c); + detachstack(c); + c->mon = m; + c->tags = m->tagset[m->seltags]; + attach(c); + attachstack(c); + selmon = m; + focus(c); + } + + c->isfloating = 1; + if (riodraw_borders) + resizeclient(c, x, y, w - (c->bw * 2), h - (c->bw * 2)); + else + resizeclient(c, x - c->bw, y - c->bw, w, h); + drawbar(c->mon); + arrange(c->mon); + + riodimensions[3] = -1; + riopid = 0; +} + +/* drag out an area using slop and resize the selected window to it */ +void +rioresize(const Arg *arg) +{ + Client *c = (arg && arg->v ? (Client*)arg->v : selmon->sel); + if (c) + riodraw(c, slopresizestyle); +} + +/* Spawn a new window and drag out an area using slop to position it while the window is + * initialising in the background. */ +void +riospawn(const Arg *arg) +{ + riopid = spawncmd(arg); + riodraw(NULL, slopspawnstyle); +} + +void +riospawnsync(const Arg *arg) +{ + if (riodraw(NULL, slopspawnstyle)) + riopid = spawncmd(arg); +} \ No newline at end of file diff --git a/suckless/dwm/patch/riodraw.h b/suckless/dwm/patch/riodraw.h new file mode 100644 index 00000000..91788049 --- /dev/null +++ b/suckless/dwm/patch/riodraw.h @@ -0,0 +1,5 @@ +static int riodraw(Client *c, const char slopstyle[]); +static void rioposition(Client *c, int x, int y, int w, int h); +static void rioresize(const Arg *arg); +static void riospawn(const Arg *arg); +static void riospawnsync(const Arg *arg); diff --git a/suckless/dwm/patch/rotatestack.c b/suckless/dwm/patch/rotatestack.c new file mode 100644 index 00000000..d2f7d508 --- /dev/null +++ b/suckless/dwm/patch/rotatestack.c @@ -0,0 +1,52 @@ +void +enqueue(Client *c) +{ + Client *l; + for (l = c->mon->clients; l && l->next; l = l->next); + if (l) { + l->next = c; + c->next = NULL; + } +} + +void +enqueuestack(Client *c) +{ + Client *l; + for (l = c->mon->stack; l && l->snext; l = l->snext); + if (l) { + l->snext = c; + c->snext = NULL; + } +} + +void +rotatestack(const Arg *arg) +{ + Client *c = NULL, *f; + + if (!selmon->sel) + return; + f = selmon->sel; + if (arg->i > 0) { + for (c = nexttiled(selmon->clients); c && nexttiled(c->next); c = nexttiled(c->next)); + if (c){ + detach(c); + attach(c); + detachstack(c); + attachstack(c); + } + } else { + if ((c = nexttiled(selmon->clients))){ + detach(c); + enqueue(c); + detachstack(c); + enqueuestack(c); + } + } + if (c){ + arrange(selmon); + focus(f); + restack(selmon); + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/rotatestack.h b/suckless/dwm/patch/rotatestack.h new file mode 100644 index 00000000..c0661fa0 --- /dev/null +++ b/suckless/dwm/patch/rotatestack.h @@ -0,0 +1,3 @@ +static void enqueue(Client *c); +static void enqueuestack(Client *c); +static void rotatestack(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/roundedcorners.c b/suckless/dwm/patch/roundedcorners.c new file mode 100644 index 00000000..56c54c84 --- /dev/null +++ b/suckless/dwm/patch/roundedcorners.c @@ -0,0 +1,50 @@ +#include + +void drawroundedcorners(Client *c) +{ + if (corner_radius <= 0 || !c || c->isfullscreen) + return; + + Window win; + win = c->win; + if (!win) + return; + + XWindowAttributes win_attr; + if (!XGetWindowAttributes(dpy, win, &win_attr)) + return; + + int dia = 2 * corner_radius; + int w = c->w; + int h = c->h; + if (w < dia || h < dia) + return; + + Pixmap mask; + mask = XCreatePixmap(dpy, win, w, h, 1); + if (!mask) + return; + + XGCValues xgcv; + GC shape_gc; + shape_gc = XCreateGC(dpy, mask, 0, &xgcv); + + if (!shape_gc) { + XFreePixmap(dpy, mask); + free(shape_gc); + return; + } + + XSetForeground(dpy, shape_gc, 0); + XFillRectangle(dpy, mask, shape_gc, 0, 0, w, h); + XSetForeground(dpy, shape_gc, 1); + XFillArc(dpy, mask, shape_gc, 0, 0, dia, dia, 0, 23040); + XFillArc(dpy, mask, shape_gc, w-dia-1, 0, dia, dia, 0, 23040); + XFillArc(dpy, mask, shape_gc, 0, h-dia-1, dia, dia, 0, 23040); + XFillArc(dpy, mask, shape_gc, w-dia-1, h-dia-1, dia, dia, 0, 23040); + XFillRectangle(dpy, mask, shape_gc, corner_radius, 0, w-dia, h); + XFillRectangle(dpy, mask, shape_gc, 0, corner_radius, w, h-dia); + XShapeCombineMask(dpy, win, ShapeBounding, 0, 0, mask, ShapeSet); + XFreePixmap(dpy, mask); + XFreeGC(dpy, shape_gc); +} \ No newline at end of file diff --git a/suckless/dwm/patch/roundedcorners.h b/suckless/dwm/patch/roundedcorners.h new file mode 100644 index 00000000..40f7549e --- /dev/null +++ b/suckless/dwm/patch/roundedcorners.h @@ -0,0 +1 @@ +static void drawroundedcorners(Client *c); \ No newline at end of file diff --git a/suckless/dwm/patch/scratchpad.c b/suckless/dwm/patch/scratchpad.c new file mode 100644 index 00000000..2034d0d4 --- /dev/null +++ b/suckless/dwm/patch/scratchpad.c @@ -0,0 +1,76 @@ +void +removescratch(const Arg *arg) +{ + Client *c = selmon->sel; + if (!c) + return; + unsigned int scratchtag = SPTAG(arg->ui); + c->tags = c->mon->tagset[c->mon->seltags] ^ scratchtag; + arrange(c->mon); +} + +void +setscratch(const Arg *arg) +{ + Client *c = selmon->sel; + if (!c) + return; + unsigned int scratchtag = SPTAG(arg->ui); + c->tags = scratchtag; + arrange(c->mon); +} + +void +togglescratch(const Arg *arg) +{ + Client *c = NULL, *next = NULL, *found = NULL; + Monitor *mon; + unsigned int scratchtag = SPTAG(arg->ui); + unsigned int newtagset = 0; + int nh = 0, nw = 0; + Arg sparg = {.v = scratchpads[arg->ui].cmd}; + + for (mon = mons; mon; mon = mon->next) { + for (c = mon->clients; c; c = next) { + next = c->next; + if (!(c->tags & scratchtag)) + continue; + + found = c; + + if (HIDDEN(c)) { + XMapWindow(dpy, c->win); + setclientstate(c, NormalState); + newtagset = 0; + } else + newtagset = selmon->tagset[selmon->seltags] ^ scratchtag; + + if (c->mon != selmon) { + if (c->mon->tagset[c->mon->seltags] & SPTAGMASK) + c->mon->tagset[c->mon->seltags] ^= scratchtag; + if (c->w > selmon->ww) + nw = selmon->ww - c->bw * 2; + if (c->h > selmon->wh) + nh = selmon->wh - c->bw * 2; + if (nw > 0 || nh > 0) + resizeclient(c, c->x, c->y, nw ? nw : c->w, nh ? nh : c->h); + sendmon(c, selmon); + } + } + } + + if (found) { + if (newtagset) { + selmon->tagset[selmon->seltags] = newtagset; + focus(NULL); + arrange(selmon); + } + if (ISVISIBLE(found)) { + focus(found); + restack(selmon); + } + } else { + selmon->tagset[selmon->seltags] |= scratchtag; + spawn(&sparg); + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/scratchpad.h b/suckless/dwm/patch/scratchpad.h new file mode 100644 index 00000000..42e592b3 --- /dev/null +++ b/suckless/dwm/patch/scratchpad.h @@ -0,0 +1,8 @@ +typedef struct { + const char *name; + const void *cmd; +} Sp; + +static void removescratch(const Arg *arg); +static void setscratch(const Arg *arg); +static void togglescratch(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/scratchpad_alt_1.c b/suckless/dwm/patch/scratchpad_alt_1.c new file mode 100644 index 00000000..c1301c91 --- /dev/null +++ b/suckless/dwm/patch/scratchpad_alt_1.c @@ -0,0 +1,92 @@ +static Client * scratchpad_last_showed = NULL; + +static void scratchpad_hide () +{ + if (selmon->sel) + { + selmon->sel->tags = SCRATCHPAD_MASK; + focus(NULL); + arrange(selmon); + } +} + +static _Bool scratchpad_last_showed_is_killed (void) +{ + _Bool killed = 1; + for (Client * c = selmon->clients; c != NULL; c = c->next) + { + if (c == scratchpad_last_showed) + { + killed = 0; + break; + } + } + return killed; +} + +static void scratchpad_remove () +{ + if (selmon->sel && scratchpad_last_showed != NULL && selmon->sel == scratchpad_last_showed) + scratchpad_last_showed = NULL; +} + +static void scratchpad_show () +{ + if (scratchpad_last_showed == NULL || scratchpad_last_showed_is_killed ()) + scratchpad_show_first (); + else + { + if (scratchpad_last_showed->tags != SCRATCHPAD_MASK) + { + scratchpad_last_showed->tags = SCRATCHPAD_MASK; + focus(NULL); + arrange(selmon); + } + else + { + _Bool found_current = 0; + _Bool found_next = 0; + for (Client * c = selmon->clients; c != NULL; c = c->next) + { + if (found_current == 0) + { + if (c == scratchpad_last_showed) + { + found_current = 1; + continue; + } + } + else + { + if (c->tags == SCRATCHPAD_MASK) + { + found_next = 1; + scratchpad_show_client (c); + break; + } + } + } + if (found_next == 0) scratchpad_show_first (); + } + } +} + +static void scratchpad_show_client (Client * c) +{ + scratchpad_last_showed = c; + c->tags = selmon->tagset[selmon->seltags]; + focus(c); + arrange(selmon); +} + +static void scratchpad_show_first (void) +{ + for (Client * c = selmon->clients; c != NULL; c = c->next) + { + if (c->tags == SCRATCHPAD_MASK) + { + scratchpad_show_client (c); + break; + } + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/scratchpad_alt_1.h b/suckless/dwm/patch/scratchpad_alt_1.h new file mode 100644 index 00000000..5cc2e2f8 --- /dev/null +++ b/suckless/dwm/patch/scratchpad_alt_1.h @@ -0,0 +1,8 @@ +#define SCRATCHPAD_MASK (1u << NUMTAGS) + +static void scratchpad_hide (); +static _Bool scratchpad_last_showed_is_killed (void); +static void scratchpad_remove (); +static void scratchpad_show (); +static void scratchpad_show_client (Client * c); +static void scratchpad_show_first (void); \ No newline at end of file diff --git a/suckless/dwm/patch/selfrestart.c b/suckless/dwm/patch/selfrestart.c new file mode 100644 index 00000000..c3b88c1a --- /dev/null +++ b/suckless/dwm/patch/selfrestart.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include + +/** + * Magically finds the current's executable path + * + * I'm doing the do{}while(); trick because Linux (what I'm running) is not + * POSIX compilant and so lstat() cannot be trusted on /proc entries + * + * @return char* the path of the current executable + */ +char *get_dwm_path() +{ + struct stat s; + int r, length, rate = 42; + char *path = NULL; + + if (lstat("/proc/self/exe", &s) == -1) { + perror("lstat:"); + return NULL; + } + + length = s.st_size + 1 - rate; + + do + { + length+=rate; + + free(path); + path = malloc(sizeof(char) * length); + + if (path == NULL){ + perror("malloc:"); + return NULL; + } + + r = readlink("/proc/self/exe", path, length); + + if (r == -1){ + perror("readlink:"); + return NULL; + } + } while (r >= length); + + path[r] = '\0'; + + return path; +} + +/** + * self-restart + * + * Initially inspired by: Yu-Jie Lin + * https://sites.google.com/site/yjlnotes/notes/dwm + */ +void self_restart(const Arg *arg) +{ + char *const argv[] = {get_dwm_path(), NULL}; + + if (argv[0] == NULL) { + return; + } + + execv(argv[0], argv); +} diff --git a/suckless/dwm/patch/selfrestart.h b/suckless/dwm/patch/selfrestart.h new file mode 100644 index 00000000..4af2436e --- /dev/null +++ b/suckless/dwm/patch/selfrestart.h @@ -0,0 +1,2 @@ +char *get_dwm_path(); +void self_restart(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/setborderpx.c b/suckless/dwm/patch/setborderpx.c new file mode 100644 index 00000000..320aaa43 --- /dev/null +++ b/suckless/dwm/patch/setborderpx.c @@ -0,0 +1,44 @@ +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; + + #if BAR_BORDER_PATCH + for (bar = selmon->bar; bar; bar = bar->next) { + bar->bh = bar->bh - 2 * bar->borderpx + 2 * selmon->borderpx; + bar->borderpx = selmon->borderpx; + } + updatebarpos(selmon); + for (bar = selmon->bar; bar; bar = bar->next) + XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh); + #endif // BAR_BORDER_PATCH + + for (c = selmon->clients; c; c = c->next) + { + if (c->bw + arg->i < 0) + c->bw = 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); +} diff --git a/suckless/dwm/patch/setborderpx.h b/suckless/dwm/patch/setborderpx.h new file mode 100644 index 00000000..c598066b --- /dev/null +++ b/suckless/dwm/patch/setborderpx.h @@ -0,0 +1 @@ +static void setborderpx(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/shiftview.c b/suckless/dwm/patch/shiftview.c new file mode 100644 index 00000000..72d5b364 --- /dev/null +++ b/suckless/dwm/patch/shiftview.c @@ -0,0 +1,18 @@ +void +shiftview(const Arg *arg) +{ + Arg shifted; + #if SCRATCHPADS_PATCH + unsigned int seltagset = selmon->tagset[selmon->seltags] & ~SPTAGMASK; + #else + unsigned int seltagset = selmon->tagset[selmon->seltags]; + #endif // SCRATCHPADS_PATCH + if (arg->i > 0) // left circular shift + shifted.ui = (seltagset << arg->i) + | (seltagset >> (NUMTAGS - arg->i)); + else // right circular shift + shifted.ui = seltagset >> -arg->i + | seltagset << (NUMTAGS + arg->i); + + view(&shifted); +} diff --git a/suckless/dwm/patch/shiftview.h b/suckless/dwm/patch/shiftview.h new file mode 100644 index 00000000..cace70eb --- /dev/null +++ b/suckless/dwm/patch/shiftview.h @@ -0,0 +1 @@ +static void shiftview(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/shiftviewclients.c b/suckless/dwm/patch/shiftviewclients.c new file mode 100644 index 00000000..04378eff --- /dev/null +++ b/suckless/dwm/patch/shiftviewclients.c @@ -0,0 +1,42 @@ +void +shiftviewclients(const Arg *arg) +{ + Arg shifted; + Client *c; + unsigned int tagmask = 0; + + for (c = selmon->clients; c; c = c->next) + #if SCRATCHPADS_PATCH + if (!(c->tags & SPTAGMASK)) + tagmask = tagmask | c->tags; + #elif SCRATCHPAD_ALT_1_PATCH + if (!(c->tags & SCRATCHPAD_MASK)) + tagmask = tagmask | c->tags; + #else + tagmask = tagmask | c->tags; + #endif // SCRATCHPADS_PATCH + + #if SCRATCHPADS_PATCH + shifted.ui = selmon->tagset[selmon->seltags] & ~SPTAGMASK; + #else + shifted.ui = selmon->tagset[selmon->seltags]; + #endif // SCRATCHPADS_PATCH + if (arg->i > 0) // left circular shift + do { + shifted.ui = (shifted.ui << arg->i) + | (shifted.ui >> (NUMTAGS - arg->i)); + #if SCRATCHPADS_PATCH + shifted.ui &= ~SPTAGMASK; + #endif // SCRATCHPADS_PATCH + } while (tagmask && !(shifted.ui & tagmask)); + else // right circular shift + do { + shifted.ui = (shifted.ui >> (- arg->i) + | shifted.ui << (NUMTAGS + arg->i)); + #if SCRATCHPADS_PATCH + shifted.ui &= ~SPTAGMASK; + #endif // SCRATCHPADS_PATCH + } while (tagmask && !(shifted.ui & tagmask)); + + view(&shifted); +} \ No newline at end of file diff --git a/suckless/dwm/patch/shiftviewclients.h b/suckless/dwm/patch/shiftviewclients.h new file mode 100644 index 00000000..ddff8265 --- /dev/null +++ b/suckless/dwm/patch/shiftviewclients.h @@ -0,0 +1 @@ +static void shiftviewclients(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/sizehints_ruled.c b/suckless/dwm/patch/sizehints_ruled.c new file mode 100644 index 00000000..885707ff --- /dev/null +++ b/suckless/dwm/patch/sizehints_ruled.c @@ -0,0 +1,24 @@ +void +checkfloatingrules(Client *c) +{ + const char *class, *instance; + unsigned int i; + const Rule *r; + XClassHint ch = { NULL, NULL }; + + XGetClassHint(dpy, c->win, &ch); + class = ch.res_class ? ch.res_class : broken; + instance = ch.res_name ? ch.res_name : broken; + + for (i = 0; i < LENGTH(rules); i++) { + r = &rules[i]; + if ((!r->title || strstr(c->name, r->title)) + && (!r->class || strstr(class, r->class)) + && (!r->instance || strstr(instance, r->instance))) + c->isfloating = r->isfloating; + } + if (ch.res_class) + XFree(ch.res_class); + if (ch.res_name) + XFree(ch.res_name); +} diff --git a/suckless/dwm/patch/sizehints_ruled.h b/suckless/dwm/patch/sizehints_ruled.h new file mode 100644 index 00000000..d21b2e49 --- /dev/null +++ b/suckless/dwm/patch/sizehints_ruled.h @@ -0,0 +1 @@ +static void checkfloatingrules(Client *c); \ No newline at end of file diff --git a/suckless/dwm/patch/sortscreens.c b/suckless/dwm/patch/sortscreens.c new file mode 100644 index 00000000..62508481 --- /dev/null +++ b/suckless/dwm/patch/sortscreens.c @@ -0,0 +1,15 @@ +void +sortscreens(XineramaScreenInfo *screens, int n) +{ + int i, j; + XineramaScreenInfo *screen = ecalloc(1, sizeof(XineramaScreenInfo)); + + for (i = 0; i < n; i++) + for (j = i + 1; j < n; j++) + if (RIGHTOF(screens[i], screens[j])) { + memcpy(&screen[0], &screens[i], sizeof(XineramaScreenInfo)); + memcpy(&screens[i], &screens[j], sizeof(XineramaScreenInfo)); + memcpy(&screens[j], &screen[0], sizeof(XineramaScreenInfo)); + } + XFree(screen); +} \ No newline at end of file diff --git a/suckless/dwm/patch/sortscreens.h b/suckless/dwm/patch/sortscreens.h new file mode 100644 index 00000000..d829cdf2 --- /dev/null +++ b/suckless/dwm/patch/sortscreens.h @@ -0,0 +1,3 @@ +#define RIGHTOF(a,b) (a.y_org > b.y_org) || ((a.y_org == b.y_org) && (a.x_org > b.x_org)) + +static void sortscreens(XineramaScreenInfo *screens, int n); \ No newline at end of file diff --git a/suckless/dwm/patch/stacker.c b/suckless/dwm/patch/stacker.c new file mode 100644 index 00000000..1582cf66 --- /dev/null +++ b/suckless/dwm/patch/stacker.c @@ -0,0 +1,106 @@ +void +focusstack(const Arg *arg) +{ + int i = stackpos(arg); + Client *c, *p; + + if (i < 0) + return; + + #if ALWAYSFULLSCREEN_PATCH + if (!selmon->sel || selmon->sel->isfullscreen) + return; + #endif // ALWAYSFULLSCREEN_PATCH + + #if BAR_WINTITLEACTIONS_PATCH + for (p = NULL, c = selmon->clients; c && (i || !ISVISIBLE(c) || HIDDEN(c)); + i -= (ISVISIBLE(c) && !HIDDEN(c) ? 1 : 0), p = c, c = c->next); + #else + for (p = NULL, c = selmon->clients; c && (i || !ISVISIBLE(c)); + i -= (ISVISIBLE(c) ? 1 : 0), p = c, c = c->next); + #endif // BAR_WINTITLEACTIONS_PATCH + focus(c ? c : p); + restack(selmon); +} + +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 BAR_WINTITLEACTIONS_PATCH + if (!(i -= (ISVISIBLE(c) && !HIDDEN(c) && c != sel))) + #else + if (!(i -= (ISVISIBLE(c) && c != sel))) + #endif // BAR_WINTITLEACTIONS_PATCH + break; + c = c ? c : p; + detach(sel); + sel->next = c->next; + c->next = sel; + } + arrange(selmon); +} + +int +stackpos(const Arg *arg) +{ + int n, i; + Client *c, *l; + + if (!selmon->clients) + return -1; + + #if BAR_WINTITLEACTIONS_PATCH + if (arg->i == PREVSEL) { + for (l = selmon->stack; l && (!ISVISIBLE(l) || HIDDEN(l) || l == selmon->sel); l = l->snext); + if (!l) + return -1; + for (i = 0, c = selmon->clients; c != l; i += (ISVISIBLE(c) && !HIDDEN(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) && !HIDDEN(c) ? 1 : 0), c = c->next); + for (n = i; c; n += (ISVISIBLE(c) && !HIDDEN(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) && !HIDDEN(c) ? 1 : 0), c = c->next); + return MAX(i + arg->i, 0); + } + else + return arg->i; + #else // !BAR_WINTITLEACTIONS_PATCH + 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; + #endif // BAR_WINTITLEACTIONS_PATCH +} diff --git a/suckless/dwm/patch/stacker.h b/suckless/dwm/patch/stacker.h new file mode 100644 index 00000000..0a064613 --- /dev/null +++ b/suckless/dwm/patch/stacker.h @@ -0,0 +1,10 @@ +#define GETINC(X) ((X) - 2000) +#define INC(X) ((X) + 2000) +#define ISINC(X) ((X) > 1000 && (X) < 3000) +#define PREVSEL 3000 +#define MOD(N,M) ((N)%(M) < 0 ? (N)%(M) + (M) : (N)%(M)) +#define TRUNC(X,A,B) (MAX((A), MIN((X), (B)))) + +static void focusstack(const Arg *arg); +static void pushstack(const Arg *arg); +static int stackpos(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/sticky.c b/suckless/dwm/patch/sticky.c new file mode 100644 index 00000000..54bd4031 --- /dev/null +++ b/suckless/dwm/patch/sticky.c @@ -0,0 +1,8 @@ +void +togglesticky(const Arg *arg) +{ + if (!selmon->sel) + return; + selmon->sel->issticky = !selmon->sel->issticky; + arrange(selmon); +} \ No newline at end of file diff --git a/suckless/dwm/patch/sticky.h b/suckless/dwm/patch/sticky.h new file mode 100644 index 00000000..a7c35ab9 --- /dev/null +++ b/suckless/dwm/patch/sticky.h @@ -0,0 +1 @@ +static void togglesticky(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/swallow.c b/suckless/dwm/patch/swallow.c new file mode 100644 index 00000000..84dda8c4 --- /dev/null +++ b/suckless/dwm/patch/swallow.c @@ -0,0 +1,205 @@ +#include +#include +#ifdef __OpenBSD__ +#include +#include +#endif /* __OpenBSD__ */ + +static int scanner; +static xcb_connection_t *xcon; + +int +swallow(Client *p, Client *c) +{ + Client *s; + + if (c->noswallow > 0 || c->isterminal) + return 0; + if (c->noswallow < 0 && !swallowfloating && c->isfloating) + return 0; + + XMapWindow(dpy, c->win); + + 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; + + XChangeProperty(dpy, c->win, netatom[NetClientList], XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(p->win), 1); + + updatetitle(p); + s = scanner ? c : p; + #if BAR_EWMHTAGS_PATCH + setfloatinghint(s); + #endif // BAR_EWMHTAGS_PATCH + XMoveResizeWindow(dpy, p->win, s->x, s->y, s->w, s->h); + arrange(p->mon); + configure(p); + updateclientlist(); + + return 1; +} + +void +unswallow(Client *c) +{ + c->win = c->swallowing->win; + + free(c->swallowing); + c->swallowing = NULL; + + XDeleteProperty(dpy, c->win, netatom[NetClientList]); + + /* 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); + #if BAR_EWMHTAGS_PATCH + setfloatinghint(c); + #endif // BAR_EWMHTAGS_PATCH + setclientstate(c, NormalState); + focus(NULL); + arrange(c->mon); +} + +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", 1), 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 (pid_t)0; + + if (fscanf(f, "%*u %*s %*c %u", (unsigned *)&v) != 1) + v = (pid_t)0; + 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; + + c = selmon->sel; + if (c && 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; +} + +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; +} diff --git a/suckless/dwm/patch/swallow.h b/suckless/dwm/patch/swallow.h new file mode 100644 index 00000000..d44a7eac --- /dev/null +++ b/suckless/dwm/patch/swallow.h @@ -0,0 +1,7 @@ +static pid_t getparentprocess(pid_t p); +static int isdescprocess(pid_t p, pid_t c); +static int swallow(Client *p, Client *c); +static Client *swallowingclient(Window w); +static Client *termforwin(const Client *c); +static void unswallow(Client *c); +static pid_t winpid(Window w); \ No newline at end of file diff --git a/suckless/dwm/patch/swapfocus.c b/suckless/dwm/patch/swapfocus.c new file mode 100644 index 00000000..7693925a --- /dev/null +++ b/suckless/dwm/patch/swapfocus.c @@ -0,0 +1,21 @@ +void +swapfocus(const Arg *arg) +{ + if (!selmon->sel) + return; + if (selmon->pertag->prevclient[selmon->pertag->curtag] != NULL + && ISVISIBLE(selmon->pertag->prevclient[selmon->pertag->curtag])) { + focus(selmon->pertag->prevclient[selmon->pertag->curtag]); + restack(selmon->pertag->prevclient[selmon->pertag->curtag]->mon); + } + else { + Client *c = NULL; + for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); + if (!c) + for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); + if (c) { + focus(c); + restack(selmon); + } + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/swapfocus.h b/suckless/dwm/patch/swapfocus.h new file mode 100644 index 00000000..f5739886 --- /dev/null +++ b/suckless/dwm/patch/swapfocus.h @@ -0,0 +1 @@ +static void swapfocus(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/swaptags.c b/suckless/dwm/patch/swaptags.c new file mode 100644 index 00000000..c43a83f9 --- /dev/null +++ b/suckless/dwm/patch/swaptags.c @@ -0,0 +1,22 @@ +void +swaptags(const Arg *arg) +{ + unsigned int newtag = arg->ui & TAGMASK; + unsigned int curtag = selmon->tagset[selmon->seltags]; + + if (newtag == curtag || !curtag || (curtag & (curtag-1))) + return; + + for (Client *c = selmon->clients; c != NULL; c = c->next) { + if ((c->tags & newtag) || (c->tags & curtag)) + c->tags ^= curtag ^ newtag; + + if (!c->tags) + c->tags = newtag; + } + + selmon->tagset[selmon->seltags] = newtag; + + focus(NULL); + arrange(selmon); +} \ No newline at end of file diff --git a/suckless/dwm/patch/swaptags.h b/suckless/dwm/patch/swaptags.h new file mode 100644 index 00000000..150fcce7 --- /dev/null +++ b/suckless/dwm/patch/swaptags.h @@ -0,0 +1 @@ +static void swaptags(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/switchcol.c b/suckless/dwm/patch/switchcol.c new file mode 100644 index 00000000..b2fe595b --- /dev/null +++ b/suckless/dwm/patch/switchcol.c @@ -0,0 +1,28 @@ +void +switchcol(const Arg *arg) +{ + Client *c, *t; + int col = 0; + int i; + + if (!selmon->sel) + return; + for (i = 0, c = nexttiled(selmon->clients); c ; + c = nexttiled(c->next), i++) { + if (c == selmon->sel) + col = (i + 1) > selmon->nmaster; + } + if (i <= selmon->nmaster) + return; + for (c = selmon->stack; c; c = c->snext) { + if (!ISVISIBLE(c)) + continue; + for (i = 0, t = nexttiled(selmon->clients); t && t != c; + t = nexttiled(t->next), i++); + if (t && (i + 1 > selmon->nmaster) != col) { + focus(c); + restack(selmon); + break; + } + } +} \ No newline at end of file diff --git a/suckless/dwm/patch/switchcol.h b/suckless/dwm/patch/switchcol.h new file mode 100644 index 00000000..f7f5f962 --- /dev/null +++ b/suckless/dwm/patch/switchcol.h @@ -0,0 +1 @@ +static void switchcol(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/tagall.c b/suckless/dwm/patch/tagall.c new file mode 100644 index 00000000..81f44e0c --- /dev/null +++ b/suckless/dwm/patch/tagall.c @@ -0,0 +1,25 @@ +void +tagall(const Arg *arg) +{ + if (!selmon->clients) + return; + /* if parameter starts with F, just move floating windows */ + int floating_only = (char *)arg->v && ((char *)arg->v)[0] == 'F' ? 1 : 0; + int tag = (char *)arg->v ? atoi(((char *)arg->v) + floating_only) : 0; + int j; + Client* c; + if (tag >= 0 && tag < NUMTAGS) + for (c = selmon->clients; c; c = c->next) + { + if (!floating_only || c->isfloating) + for (j = 0; j < NUMTAGS; j++) + { + if (c->tags & 1 << j && selmon->tagset[selmon->seltags] & 1 << j) + { + c->tags = c->tags ^ (1 << j & TAGMASK); + c->tags = c->tags | 1 << (tag-1); + } + } + } + arrange(selmon); +} \ No newline at end of file diff --git a/suckless/dwm/patch/tagall.h b/suckless/dwm/patch/tagall.h new file mode 100644 index 00000000..09fe4d1e --- /dev/null +++ b/suckless/dwm/patch/tagall.h @@ -0,0 +1 @@ +static void tagall(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/tagallmon.c b/suckless/dwm/patch/tagallmon.c new file mode 100644 index 00000000..f863b6d3 --- /dev/null +++ b/suckless/dwm/patch/tagallmon.c @@ -0,0 +1,48 @@ +void +tagallmon(const Arg *arg) +{ + Monitor *m; + Client *c, *last, *slast, *next; + + if (!mons->next) + return; + + m = dirtomon(arg->i); + for (last = m->clients; last && last->next; last = last->next); + for (slast = m->stack; slast && slast->snext; slast = slast->snext); + + for (c = selmon->clients; c; c = next) { + next = c->next; + if (!ISVISIBLE(c)) + continue; + unfocus(c, 1, NULL); + detach(c); + detachstack(c); + c->mon = m; + c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ + c->next = NULL; + c->snext = NULL; + if (last) + last = last->next = c; + else + m->clients = last = c; + if (slast) + slast = slast->snext = c; + else + m->stack = slast = c; + if (c->isfullscreen) { + #if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH + if (c->fakefullscreen != 1) { + resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); + XRaiseWindow(dpy, c->win); + } + #elif !FAKEFULLSCREEN_PATCH + resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); + XRaiseWindow(dpy, c->win); + #endif // FAKEFULLSCREEN_CLIENT_PATCH + } + } + + focus(NULL); + arrange(NULL); +} \ No newline at end of file diff --git a/suckless/dwm/patch/tagallmon.h b/suckless/dwm/patch/tagallmon.h new file mode 100644 index 00000000..e4090242 --- /dev/null +++ b/suckless/dwm/patch/tagallmon.h @@ -0,0 +1 @@ +static void tagallmon(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/tagothermonitor.c b/suckless/dwm/patch/tagothermonitor.c new file mode 100644 index 00000000..ddeaff87 --- /dev/null +++ b/suckless/dwm/patch/tagothermonitor.c @@ -0,0 +1,43 @@ +#if IPC_PATCH || DWMC_PATCH +void +tagnextmonex(const Arg *arg) +{ + tagnextmon(&((Arg) { .ui = 1 << arg->ui })); +} + +void +tagprevmonex(const Arg *arg) +{ + tagprevmon(&((Arg) { .ui = 1 << arg->ui })); +} +#endif // IPC_PATCH | DWMC_PATCH + +void +tagnextmon(const Arg *arg) +{ + tagothermon(arg, 1); +} + +void +tagprevmon(const Arg *arg) +{ + tagothermon(arg, -1); +} + +void +tagothermon(const Arg *arg, int dir) +{ + Client *sel; + Monitor *newmon; + + if (!selmon->sel || !mons->next) + return; + sel = selmon->sel; + newmon = dirtomon(dir); + sendmon(sel, newmon); + if (arg->ui & TAGMASK) { + sel->tags = arg->ui & TAGMASK; + focus(NULL); + arrange(newmon); + } +} diff --git a/suckless/dwm/patch/tagothermonitor.h b/suckless/dwm/patch/tagothermonitor.h new file mode 100644 index 00000000..e2aa24f9 --- /dev/null +++ b/suckless/dwm/patch/tagothermonitor.h @@ -0,0 +1,8 @@ +#if IPC_PATCH || DWMC_PATCH +static void tagnextmonex(const Arg *arg); +static void tagprevmonex(const Arg *arg); +#endif // IPC_PATCH | DWMC_PATCH + +static void tagnextmon(const Arg *arg); +static void tagprevmon(const Arg *arg); +static void tagothermon(const Arg *arg, int dir); diff --git a/suckless/dwm/patch/tagswapmon.c b/suckless/dwm/patch/tagswapmon.c new file mode 100644 index 00000000..a6f8a32a --- /dev/null +++ b/suckless/dwm/patch/tagswapmon.c @@ -0,0 +1,74 @@ +void +tagswapmon(const Arg *arg) +{ + Monitor *m; + Client *c, *sc = NULL, *mc = NULL, *next; + + if (!mons->next) + return; + + m = dirtomon(arg->i); + + for (c = selmon->clients; c; c = next) { + next = c->next; + if (!ISVISIBLE(c)) + continue; + unfocus(c, 1, NULL); + detach(c); + detachstack(c); + c->next = sc; + sc = c; + } + + for (c = m->clients; c; c = next) { + next = c->next; + if (!ISVISIBLE(c)) + continue; + unfocus(c, 1, NULL); + detach(c); + detachstack(c); + c->next = mc; + mc = c; + } + + for (c = sc; c; c = next) { + next = c->next; + c->mon = m; + c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ + attach(c); + attachstack(c); + if (c->isfullscreen) { + #if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH + if (c->fakefullscreen != 1) { + resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); + XRaiseWindow(dpy, c->win); + } + #elif !FAKEFULLSCREEN_PATCH + resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); + XRaiseWindow(dpy, c->win); + #endif // FAKEFULLSCREEN_CLIENT_PATCH + } + } + + for (c = mc; c; c = next) { + next = c->next; + c->mon = selmon; + c->tags = selmon->tagset[selmon->seltags]; /* assign tags of target monitor */ + attach(c); + attachstack(c); + if (c->isfullscreen) { + #if !FAKEFULLSCREEN_PATCH && FAKEFULLSCREEN_CLIENT_PATCH + if (c->fakefullscreen != 1) { + resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); + XRaiseWindow(dpy, c->win); + } + #elif !FAKEFULLSCREEN_PATCH + resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); + XRaiseWindow(dpy, c->win); + #endif // FAKEFULLSCREEN_CLIENT_PATCH + } + } + + focus(NULL); + arrange(NULL); +} \ No newline at end of file diff --git a/suckless/dwm/patch/tagswapmon.h b/suckless/dwm/patch/tagswapmon.h new file mode 100644 index 00000000..433f4b16 --- /dev/null +++ b/suckless/dwm/patch/tagswapmon.h @@ -0,0 +1 @@ +static void tagswapmon(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/togglefullscreen.c b/suckless/dwm/patch/togglefullscreen.c new file mode 100644 index 00000000..bc1c705b --- /dev/null +++ b/suckless/dwm/patch/togglefullscreen.c @@ -0,0 +1,17 @@ +void +togglefullscreen(const Arg *arg) +{ + Client *c = selmon->sel; + if (!c) + return; + + #if FAKEFULLSCREEN_CLIENT_PATCH + if (c->fakefullscreen == 1) { // fake fullscreen --> fullscreen + c->fakefullscreen = 2; + setfullscreen(c, 1); + } else + setfullscreen(c, !c->isfullscreen); + #else + setfullscreen(c, !c->isfullscreen); + #endif // FAKEFULLSCREEN_CLIENT_PATCH +} diff --git a/suckless/dwm/patch/togglefullscreen.h b/suckless/dwm/patch/togglefullscreen.h new file mode 100644 index 00000000..7e1126af --- /dev/null +++ b/suckless/dwm/patch/togglefullscreen.h @@ -0,0 +1 @@ +static void togglefullscreen(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/transfer.c b/suckless/dwm/patch/transfer.c new file mode 100644 index 00000000..0a99f310 --- /dev/null +++ b/suckless/dwm/patch/transfer.c @@ -0,0 +1,33 @@ +void +transfer(const Arg *arg) +{ + Client *c, *mtail = selmon->clients, *stail = NULL, *insertafter; + int transfertostack = 0, i, nmasterclients; + + for (i = 0, c = selmon->clients; c; c = c->next) { + if (!ISVISIBLE(c) || c->isfloating) continue; + if (selmon->sel == c) { transfertostack = i < selmon->nmaster && selmon->nmaster != 0; } + if (i < selmon->nmaster) { nmasterclients++; mtail = c; } + stail = c; + i++; + } + if (!selmon->sel || selmon->sel->isfloating || i == 0) { + return; + } else if (transfertostack) { + selmon->nmaster = MIN(i, selmon->nmaster) - 1; + insertafter = stail; + } else { + selmon->nmaster = selmon->nmaster + 1; + insertafter = mtail; + } + if (insertafter != selmon->sel) { + detach(selmon->sel); + if (selmon->nmaster == 1 && !transfertostack) { + attach(selmon->sel); // Head prepend case + } else { + selmon->sel->next = insertafter->next; + insertafter->next = selmon->sel; + } + } + arrange(selmon); +} diff --git a/suckless/dwm/patch/transfer.h b/suckless/dwm/patch/transfer.h new file mode 100644 index 00000000..a8436dda --- /dev/null +++ b/suckless/dwm/patch/transfer.h @@ -0,0 +1 @@ +static void transfer(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/transferall.c b/suckless/dwm/patch/transferall.c new file mode 100644 index 00000000..fe126997 --- /dev/null +++ b/suckless/dwm/patch/transferall.c @@ -0,0 +1,25 @@ +void +transferall(const Arg *arg) +{ + Client *c, *n = selmon->clients, *attachfrom = NULL; + int i = 0, nstackclients = 0; + while (n) { + c = n; + n = c->next; + if (!ISVISIBLE(c) || c->isfloating) continue; + if (i >= selmon->nmaster) { + detach(c); + if (!attachfrom) { + attach(c); + } else { + c->next = attachfrom->next; + attachfrom->next = c; + } + attachfrom = c; + nstackclients++; + } + i++; + } + selmon->nmaster = nstackclients; + arrange(selmon); +} \ No newline at end of file diff --git a/suckless/dwm/patch/transferall.h b/suckless/dwm/patch/transferall.h new file mode 100644 index 00000000..55564688 --- /dev/null +++ b/suckless/dwm/patch/transferall.h @@ -0,0 +1 @@ +static void transferall(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/unfloatvisible.c b/suckless/dwm/patch/unfloatvisible.c new file mode 100644 index 00000000..8f0360de --- /dev/null +++ b/suckless/dwm/patch/unfloatvisible.c @@ -0,0 +1,14 @@ +void +unfloatvisible(const Arg *arg) +{ + Client *c; + + for (c = selmon->clients; c; c = c->next) + if (ISVISIBLE(c) && c->isfloating) + c->isfloating = c->isfixed; + + if (arg && arg->v) + setlayout(arg); + else + arrange(selmon); +} \ No newline at end of file diff --git a/suckless/dwm/patch/unfloatvisible.h b/suckless/dwm/patch/unfloatvisible.h new file mode 100644 index 00000000..690b6eff --- /dev/null +++ b/suckless/dwm/patch/unfloatvisible.h @@ -0,0 +1 @@ +static void unfloatvisible(const Arg *arg); \ No newline at end of file diff --git a/suckless/dwm/patch/vanitygaps.c b/suckless/dwm/patch/vanitygaps.c new file mode 100644 index 00000000..dd579dec --- /dev/null +++ b/suckless/dwm/patch/vanitygaps.c @@ -0,0 +1,192 @@ +/* Settings */ +#if !PERTAG_PATCH +static int enablegaps = 1; +#endif // PERTAG_PATCH + +static 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); +} + +#if IPC_PATCH || DWMC_PATCH +/* External function that takes one integer and splits it + * into four gap values: + * - outer horizontal (oh) + * - outer vertical (ov) + * - inner horizontal (ih) + * - inner vertical (iv) + * + * Each value is represented as one byte with the uppermost + * bit of each byte indicating whether or not to keep the + * current value. + * + * Example: + * + * 10000000 10000000 00001111 00001111 + * | | | | + * + keep oh + keep ov + ih 15px + iv 15px + * + * This gives an int of: + * 10000000100000000000111100001111 = 2155876111 + * + * Thus this command should set inner gaps to 15: + * xsetroot -name "fsignal:setgaps i 2155876111" + */ +static void +setgapsex(const Arg *arg) +{ + int oh = selmon->gappoh; + int ov = selmon->gappov; + int ih = selmon->gappih; + int iv = selmon->gappiv; + + if (!(arg->i & (1 << 31))) + oh = (arg->i & 0x7f000000) >> 24; + if (!(arg->i & (1 << 23))) + ov = (arg->i & 0x7f0000) >> 16; + if (!(arg->i & (1 << 15))) + ih = (arg->i & 0x7f00) >> 8; + if (!(arg->i & (1 << 7))) + iv = (arg->i & 0x7f); + + /* Auto enable gaps if disabled */ + #if PERTAG_PATCH + if (!selmon->pertag->enablegaps[selmon->pertag->curtag]) + selmon->pertag->enablegaps[selmon->pertag->curtag] = 1; + #else + if (!enablegaps) + enablegaps = 1; + #endif // PERTAG_PATCH + + setgaps(oh, ov, ih, iv); +} +#endif // IPC_PATCH | DWMC_PATCH + +static 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); +} + +static void +defaultgaps(const Arg *arg) +{ + setgaps(gappoh, gappov, gappih, gappiv); +} + +static void +incrgaps(const Arg *arg) +{ + setgaps( + selmon->gappoh + arg->i, + selmon->gappov + arg->i, + selmon->gappih + arg->i, + selmon->gappiv + arg->i + ); +} + +static void +incrigaps(const Arg *arg) +{ + setgaps( + selmon->gappoh, + selmon->gappov, + selmon->gappih + arg->i, + selmon->gappiv + arg->i + ); +} + +static void +incrogaps(const Arg *arg) +{ + setgaps( + selmon->gappoh + arg->i, + selmon->gappov + arg->i, + selmon->gappih, + selmon->gappiv + ); +} + +static void +incrohgaps(const Arg *arg) +{ + setgaps( + selmon->gappoh + arg->i, + selmon->gappov, + selmon->gappih, + selmon->gappiv + ); +} + +static void +incrovgaps(const Arg *arg) +{ + setgaps( + selmon->gappoh, + selmon->gappov + arg->i, + selmon->gappih, + selmon->gappiv + ); +} + +static void +incrihgaps(const Arg *arg) +{ + setgaps( + selmon->gappoh, + selmon->gappov, + selmon->gappih + arg->i, + selmon->gappiv + ); +} + +static void +incrivgaps(const Arg *arg) +{ + setgaps( + selmon->gappoh, + selmon->gappov, + selmon->gappih, + selmon->gappiv + arg->i + ); +} + +#if DRAGMFACT_PATCH || CENTEREDMASTER_LAYOUT || CENTEREDFLOATINGMASTER_LAYOUT || COLUMNS_LAYOUT || DECK_LAYOUT || FIBONACCI_DWINDLE_LAYOUT || FIBONACCI_SPIRAL_LAYOUT || GAPPLESSGRID_LAYOUT || NROWGRID_LAYOUT || HORIZGRID_LAYOUT || BSTACK_LAYOUT || BSTACKHORIZ_LAYOUT || GRIDMODE_LAYOUT || FLEXTILE_DELUXE_LAYOUT || TILE_LAYOUT || (VANITYGAPS_MONOCLE_PATCH && MONOCLE_LAYOUT) +static 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 +} +#endif diff --git a/suckless/dwm/patch/vanitygaps.h b/suckless/dwm/patch/vanitygaps.h new file mode 100644 index 00000000..c3eb6222 --- /dev/null +++ b/suckless/dwm/patch/vanitygaps.h @@ -0,0 +1,19 @@ +/* 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); + +/* Internals */ +#if DRAGMFACT_PATCH || CENTEREDMASTER_LAYOUT || CENTEREDFLOATINGMASTER_LAYOUT || COLUMNS_LAYOUT || DECK_LAYOUT || FIBONACCI_DWINDLE_LAYOUT || FIBONACCI_SPIRAL_LAYOUT || GAPPLESSGRID_LAYOUT || NROWGRID_LAYOUT || HORIZGRID_LAYOUT || BSTACK_LAYOUT || BSTACKHORIZ_LAYOUT || GRIDMODE_LAYOUT || FLEXTILE_DELUXE_LAYOUT || TILE_LAYOUT || (VANITYGAPS_MONOCLE_PATCH && MONOCLE_LAYOUT) +static void getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc); +#endif +static void setgaps(int oh, int ov, int ih, int iv); +#if IPC_PATCH || DWMC_PATCH +static void setgapsex(const Arg *arg); +#endif // IPC_PATCH | DWMC_PATCH \ No newline at end of file diff --git a/suckless/dwm/patch/warp.c b/suckless/dwm/patch/warp.c new file mode 100644 index 00000000..41838187 --- /dev/null +++ b/suckless/dwm/patch/warp.c @@ -0,0 +1,37 @@ +void +warp(const Client *c) +{ + Monitor *m; + Bar *bar; + int x, y; + + if (ignore_warp) + return; + + if (!c) { + XWarpPointer(dpy, None, root, 0, 0, 0, 0, selmon->wx + selmon->ww / 2, selmon->wy + selmon->wh / 2); + return; + } + + if (!getrootptr(&x, &y)) + return; + + if (!force_warp && + (x > c->x - c->bw && + y > c->y - c->bw && + x < c->x + c->w + c->bw*2 && + y < c->y + c->h + c->bw*2)) + return; + + force_warp = 0; + + for (m = mons; m; m = m->next) + for (bar = m->bar; bar; bar = bar->next) + if (x > bar->bx && + x < bar->bx + bar->bw && + y > bar->by && + y < bar->by + bar->bh) + return; + + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w / 2, c->h / 2); +} diff --git a/suckless/dwm/patch/warp.h b/suckless/dwm/patch/warp.h new file mode 100644 index 00000000..6657dc11 --- /dev/null +++ b/suckless/dwm/patch/warp.h @@ -0,0 +1 @@ +static void warp(const Client *c); \ No newline at end of file diff --git a/suckless/dwm/patch/winview.c b/suckless/dwm/patch/winview.c new file mode 100644 index 00000000..a73ee660 --- /dev/null +++ b/suckless/dwm/patch/winview.c @@ -0,0 +1,20 @@ +/* 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); +} \ No newline at end of file diff --git a/suckless/dwm/patch/winview.h b/suckless/dwm/patch/winview.h new file mode 100644 index 00000000..a2405330 --- /dev/null +++ b/suckless/dwm/patch/winview.h @@ -0,0 +1 @@ +static void winview(const Arg* arg); \ No newline at end of file diff --git a/suckless/dwm/patch/xrdb.c b/suckless/dwm/patch/xrdb.c new file mode 100644 index 00000000..e8633cd7 --- /dev/null +++ b/suckless/dwm/patch/xrdb.c @@ -0,0 +1,125 @@ +void +loadxrdb() +{ + Display *display; + char * resm; + XrmDatabase xrdb; + char *type; + XrmValue value; + + display = XOpenDisplay(NULL); + + if (display != NULL) { + resm = XResourceManagerString(display); + + if (resm != NULL) { + xrdb = XrmGetStringDatabase(resm); + + if (xrdb != NULL) { + XRDB_LOAD_COLOR("dwm.normfgcolor", normfgcolor); + XRDB_LOAD_COLOR("dwm.normbgcolor", normbgcolor); + XRDB_LOAD_COLOR("dwm.normbordercolor", normbordercolor); + XRDB_LOAD_COLOR("dwm.normfloatcolor", normfloatcolor); + XRDB_LOAD_COLOR("dwm.selfgcolor", selfgcolor); + XRDB_LOAD_COLOR("dwm.selbgcolor", selbgcolor); + XRDB_LOAD_COLOR("dwm.selbordercolor", selbordercolor); + XRDB_LOAD_COLOR("dwm.selfloatcolor", selfloatcolor); + XRDB_LOAD_COLOR("dwm.titlenormfgcolor", titlenormfgcolor); + XRDB_LOAD_COLOR("dwm.titlenormbgcolor", titlenormbgcolor); + XRDB_LOAD_COLOR("dwm.titlenormbordercolor", titlenormbordercolor); + XRDB_LOAD_COLOR("dwm.titlenormfloatcolor", titlenormfloatcolor); + XRDB_LOAD_COLOR("dwm.titleselfgcolor", titleselfgcolor); + XRDB_LOAD_COLOR("dwm.titleselbgcolor", titleselbgcolor); + XRDB_LOAD_COLOR("dwm.titleselbordercolor", titleselbordercolor); + XRDB_LOAD_COLOR("dwm.titleselfloatcolor", titleselfloatcolor); + XRDB_LOAD_COLOR("dwm.tagsnormfgcolor", tagsnormfgcolor); + XRDB_LOAD_COLOR("dwm.tagsnormbgcolor", tagsnormbgcolor); + XRDB_LOAD_COLOR("dwm.tagsnormbordercolor", tagsnormbordercolor); + XRDB_LOAD_COLOR("dwm.tagsnormfloatcolor", tagsnormfloatcolor); + XRDB_LOAD_COLOR("dwm.tagsselfgcolor", tagsselfgcolor); + XRDB_LOAD_COLOR("dwm.tagsselbgcolor", tagsselbgcolor); + XRDB_LOAD_COLOR("dwm.tagsselbordercolor", tagsselbordercolor); + XRDB_LOAD_COLOR("dwm.tagsselfloatcolor", tagsselfloatcolor); + XRDB_LOAD_COLOR("dwm.hidfgcolor", hidfgcolor); + XRDB_LOAD_COLOR("dwm.hidbgcolor", hidbgcolor); + XRDB_LOAD_COLOR("dwm.hidbordercolor", hidbordercolor); + XRDB_LOAD_COLOR("dwm.hidfloatcolor", hidfloatcolor); + XRDB_LOAD_COLOR("dwm.urgfgcolor", urgfgcolor); + XRDB_LOAD_COLOR("dwm.urgbgcolor", urgbgcolor); + XRDB_LOAD_COLOR("dwm.urgbordercolor", urgbordercolor); + XRDB_LOAD_COLOR("dwm.urgfloatcolor", urgfloatcolor); + #if BAR_FLEXWINTITLE_PATCH + XRDB_LOAD_COLOR("dwm.normTTBbgcolor", normTTBbgcolor); + XRDB_LOAD_COLOR("dwm.normLTRbgcolor", normLTRbgcolor); + XRDB_LOAD_COLOR("dwm.normMONObgcolor", normMONObgcolor); + XRDB_LOAD_COLOR("dwm.normGRIDbgcolor", normGRIDbgcolor); + XRDB_LOAD_COLOR("dwm.normGRD1bgcolor", normGRD1bgcolor); + XRDB_LOAD_COLOR("dwm.normGRD2bgcolor", normGRD2bgcolor); + XRDB_LOAD_COLOR("dwm.normGRDMbgcolor", normGRDMbgcolor); + XRDB_LOAD_COLOR("dwm.normHGRDbgcolor", normHGRDbgcolor); + XRDB_LOAD_COLOR("dwm.normDWDLbgcolor", normDWDLbgcolor); + XRDB_LOAD_COLOR("dwm.normSPRLbgcolor", normSPRLbgcolor); + XRDB_LOAD_COLOR("dwm.normfloatbgcolor", normfloatbgcolor); + XRDB_LOAD_COLOR("dwm.actTTBbgcolor", actTTBbgcolor); + XRDB_LOAD_COLOR("dwm.actLTRbgcolor", actLTRbgcolor); + XRDB_LOAD_COLOR("dwm.actMONObgcolor", actMONObgcolor); + XRDB_LOAD_COLOR("dwm.actGRIDbgcolor", actGRIDbgcolor); + XRDB_LOAD_COLOR("dwm.actGRD1bgcolor", actGRD1bgcolor); + XRDB_LOAD_COLOR("dwm.actGRD2bgcolor", actGRD2bgcolor); + XRDB_LOAD_COLOR("dwm.actGRDMbgcolor", actGRDMbgcolor); + XRDB_LOAD_COLOR("dwm.actHGRDbgcolor", actHGRDbgcolor); + XRDB_LOAD_COLOR("dwm.actDWDLbgcolor", actDWDLbgcolor); + XRDB_LOAD_COLOR("dwm.actSPRLbgcolor", actSPRLbgcolor); + XRDB_LOAD_COLOR("dwm.actfloatbgcolor", actfloatbgcolor); + XRDB_LOAD_COLOR("dwm.selTTBbgcolor", selTTBbgcolor); + XRDB_LOAD_COLOR("dwm.selLTRbgcolor", selLTRbgcolor); + XRDB_LOAD_COLOR("dwm.selMONObgcolor", selMONObgcolor); + XRDB_LOAD_COLOR("dwm.selGRIDbgcolor", selGRIDbgcolor); + XRDB_LOAD_COLOR("dwm.selGRD1bgcolor", selGRD1bgcolor); + XRDB_LOAD_COLOR("dwm.selGRD2bgcolor", selGRD2bgcolor); + XRDB_LOAD_COLOR("dwm.selGRDMbgcolor", selGRDMbgcolor); + XRDB_LOAD_COLOR("dwm.selHGRDbgcolor", selHGRDbgcolor); + XRDB_LOAD_COLOR("dwm.selDWDLbgcolor", selDWDLbgcolor); + XRDB_LOAD_COLOR("dwm.selSPRLbgcolor", selSPRLbgcolor); + XRDB_LOAD_COLOR("dwm.selfloatbgcolor", selfloatbgcolor); + #endif // BAR_FLEXWINTITLE_PATCH + #if BAR_STATUS2D_XRDB_TERMCOLORS_PATCH && BAR_STATUS2D_PATCH + XRDB_LOAD_COLOR("color0", termcol0); + XRDB_LOAD_COLOR("color1", termcol1); + XRDB_LOAD_COLOR("color2", termcol2); + XRDB_LOAD_COLOR("color3", termcol3); + XRDB_LOAD_COLOR("color4", termcol4); + XRDB_LOAD_COLOR("color5", termcol5); + XRDB_LOAD_COLOR("color6", termcol6); + XRDB_LOAD_COLOR("color7", termcol7); + XRDB_LOAD_COLOR("color8", termcol8); + XRDB_LOAD_COLOR("color9", termcol9); + XRDB_LOAD_COLOR("color10", termcol10); + XRDB_LOAD_COLOR("color11", termcol11); + XRDB_LOAD_COLOR("color12", termcol12); + XRDB_LOAD_COLOR("color13", termcol13); + XRDB_LOAD_COLOR("color14", termcol14); + XRDB_LOAD_COLOR("color15", termcol15); + #endif // BAR_STATUS2D_XRDB_TERMCOLORS_PATCH + } + } + } + + XCloseDisplay(display); +} + +void +xrdb(const Arg *arg) +{ + loadxrdb(); + int i; + for (i = 0; i < LENGTH(colors); i++) + scheme[i] = drw_scm_create(drw, colors[i], + #if BAR_ALPHA_PATCH + alphas[i], + #endif // BAR_ALPHA_PATCH + ColCount + ); + focus(NULL); + arrange(NULL); +} \ No newline at end of file diff --git a/suckless/dwm/patch/xrdb.h b/suckless/dwm/patch/xrdb.h new file mode 100644 index 00000000..304f2e22 --- /dev/null +++ b/suckless/dwm/patch/xrdb.h @@ -0,0 +1,21 @@ +#include + +#define XRDB_LOAD_COLOR(R,V) if (XrmGetResource(xrdb, R, NULL, &type, &value) == True) { \ + if (value.addr != NULL && strnlen(value.addr, 8) == 7 && value.addr[0] == '#') { \ + int i = 1; \ + for (; i <= 6; i++) { \ + if (value.addr[i] < 48) break; \ + if (value.addr[i] > 57 && value.addr[i] < 65) break; \ + if (value.addr[i] > 70 && value.addr[i] < 97) break; \ + if (value.addr[i] > 102) break; \ + } \ + if (i == 7) { \ + strncpy(V, value.addr, 7); \ + V[7] = '\0'; \ + } \ + } \ + } + +static void loadxrdb(void); +static void xrdb(const Arg *arg); + diff --git a/suckless/dwm/patch/zoomswap.c b/suckless/dwm/patch/zoomswap.c new file mode 100644 index 00000000..d7f57c4f --- /dev/null +++ b/suckless/dwm/patch/zoomswap.c @@ -0,0 +1,13 @@ + +#if !PERTAG_PATCH +static Client *prevzoom = NULL; +#endif // PERTAG_PATCH + +Client * +findbefore(Client *c) { + Client *p; + if (!c || c == c->mon->clients) + return NULL; + for (p = c->mon->clients; p && p->next != c; p = p->next); + return p; +} \ No newline at end of file diff --git a/suckless/dwm/patch/zoomswap.h b/suckless/dwm/patch/zoomswap.h new file mode 100644 index 00000000..21cc8487 --- /dev/null +++ b/suckless/dwm/patch/zoomswap.h @@ -0,0 +1 @@ +static Client *findbefore(Client *c); \ No newline at end of file diff --git a/suckless/dwm/patches.def.h b/suckless/dwm/patches.def.h new file mode 100644 index 00000000..0a27b1cc --- /dev/null +++ b/suckless/dwm/patches.def.h @@ -0,0 +1,1178 @@ +/* + * This file contains patch control flags. + * + * In principle you should be able to mix and match any patches + * you may want. In cases where patches are logically incompatible + * one patch may take precedence over the other as noted in the + * relevant descriptions. + * + * Although layouts typically come as patches they are differentiated + * here for grouping purposes. + */ + +/** + * Bar modules + */ + +/* Enhanced taskbar that shows the titles of all visible windows in the status bar + * and allows focus / hiding / unhiding of windows by clicking on the status bar. + * Awesomebar takes precedence over fancybar. + * https://dwm.suckless.org/patches/awesomebar/ + */ +#define BAR_AWESOMEBAR_PATCH 0 + +/* This patch depends on statuscmd patch and adds integration with a (patched) dwmblocks + * instance to give a clickable status bar. + * Patch: https://gist.github.com/danbyl/54f7c1d57fc6507242a95b71c3d8fdea + * dwmblocks: https://github.com/torrinfail/dwmblocks + */ +#define BAR_DWMBLOCKS_PATCH 0 + +/* This patch shows the titles of all visible windows in the status bar + * (as opposed to showing only the selected one). + * Awesomebar takes precedence over fancybar. Fancybar takes precedence over + * the centeredwindowname patch. + * https://dwm.suckless.org/patches/fancybar/ + */ +#define BAR_FANCYBAR_PATCH 0 + +/* Being an evolution of the bartabgroups patch the flexwintitle patch specifically + * taps into the many layout options that flextile-deluxe offers to produce a window + * title section in the bar that is representative of what is shown on screen. + */ +#define BAR_FLEXWINTITLE_PATCH 0 + +/* This patch adds a context menu for layout switching. + * - xmenu needs to be installed. + * - Edit layoutmenu.sh with the installed layouts and with correct indexes. + * - Place layoutmenu.sh in PATH. + * - The text of the menu items is for display only. Name them however you want. + * https://dwm.suckless.org/patches/layoutmenu/ + */ +#define BAR_LAYOUTMENU_PATCH 0 + +/* Show layout symbol in bar */ +#define BAR_LTSYMBOL_PATCH 1 + +/* Adds powerline arrows for the status. + * This uses statuscolors logic for choosing colors for the powerline. As these markers + * are also control characters there is no explicit statuscmd support for this patch. + * + * Powerline separators are defined as: + * |\xXX (creates a hard edge) + * <\xXX (creates a less than arrow) + * /\xXX (creates a diagonal line) + * + * Examples: + * xsetroot -name "$(echo -e '<\x01a<\x02b<\x03c')" + * xsetroot -name "$(echo -e '/\x01d/\x02d/\x03f')" + * + * https://gitlab.com/udiboy1209-suckless/dwm/-/commit/071f5063e8ac4280666828179f92788d893eea40#4b1a539194be7467cefbda22f675a3b7c19ceca7 + * https://dwm.suckless.org/patches/statuscolors/ + */ +#define BAR_POWERLINE_STATUS_PATCH 0 + +/* Adds powerline arrows for the tags. + * https://gitlab.com/udiboy1209-suckless/dwm/-/commit/071f5063e8ac4280666828179f92788d893eea40#4b1a539194be7467cefbda22f675a3b7c19ceca7 + */ +#define BAR_POWERLINE_TAGS_PATCH 0 + +/* Alters the tags powerline to use forward slash instead of arrows */ +#define BAR_POWERLINE_TAGS_SLASH_PATCH 0 + +/* This patch turns the titlebar area into a mfact-respecting tabbar showing each client's title. + * https://dwm.suckless.org/patches/bartabgroups/ + */ +#define BAR_TABGROUPS_PATCH 0 + +/* This patch adds an option to place tags in rows like in many other window managers. + * https://dwm.suckless.org/patches/taggrid/ + */ +#define BAR_TAGGRID_PATCH 0 + +/* Show status in bar */ +#define BAR_STATUS_PATCH 1 + +/* This patch adds a clickable button to the left hand side of the statusbar. + * https://dwm.suckless.org/patches/statusbutton/ + */ +#define BAR_STATUSBUTTON_PATCH 0 + +/* This patch adds the ability to execute shell commands based on the mouse button and position + * when clicking the status bar. Refer to the website for usage. + * https://dwm.suckless.org/patches/statuscmd/ + */ +#define BAR_STATUSCMD_PATCH 0 + +/* Status2d allows colors and rectangle drawing in your dwm status bar. + * This patch is incompatible with the statuscolors patch which takes precedence. + * This patch is incompatible with the extrabar patch. + * https://dwm.suckless.org/patches/status2d/ + */ +#define BAR_STATUS2D_PATCH 0 + +/* Supplementary patch should you want to disable alpha for the status2d section */ +#define BAR_STATUS2D_NO_ALPHA_PATCH 0 + +/* Addition to the status2d patch that allows the use of terminal colors (color0 through color15) + * from xrdb in the status, allowing programs like pywal to change statusbar colors. + * This adds the C and B codes to use terminal foreground and background colors respectively. + * E.g. ^B5^ would use color5 as the background color. + * https://dwm.suckless.org/patches/status2d/ + */ +#define BAR_STATUS2D_XRDB_TERMCOLORS_PATCH 0 + +/* The systray patch adds systray for the status bar. + * https://dwm.suckless.org/patches/systray/ + */ +#define BAR_SYSTRAY_PATCH 0 + +/* Show tag symbols in bar */ +#define BAR_TAGS_PATCH 1 + +/* Show window title in bar */ +#define BAR_WINTITLE_PATCH 1 + +/* Shows window titles in the bar, but only for floating clients. + * This depends on code from the flexwintitle patch. + * Note that the configuration in config.def.h for this is merely an example. If combined + * with the corresponding hidden patch then these two will overlap unless the width of the + * modules are controlled. + */ +#define BAR_WINTITLE_FLOATING_PATCH 0 + +/* Shows window titles in the bar, but only for floating clients. + * This depends on code from the flexwintitle patch. + * Note that the configuration in config.def.h for this is merely an example. If combined + * with the corresponding floating patch then these two will overlap unless the width of the + * modules are controlled. + */ +#define BAR_WINTITLE_HIDDEN_PATCH 0 + +/* Title bar modules such as wintitle (default), fancybar and awesomebar + * do not by default add left and/or right padding as they take up the + * remaining space. These options allow you explicitly add padding should + * you need it. + */ +#define BAR_TITLE_RIGHT_PAD_PATCH 0 +#define BAR_TITLE_LEFT_PAD_PATCH 1 + +/** + * Bar options + */ + +/* This patch changes the rectangle indicating if a tag is used by a client into a bar + * above the tag name for better visibility. + * Set the tagindicatortype variable in config.h to INDICATOR_TOP_BAR to enable this. + * https://dwm.suckless.org/patches/activetagindicatorbar/ + */ +#define BAR_ACTIVETAGINDICATORBAR_PATCH N/A + +/* Alternative patch to the activetagindicatorbar patch, adds the bar below the tag + * icon rather than above. + * Set the tagindicatortype variable in config.h to INDICATOR_BOTTOM_BAR to enable this. + */ +#define BAR_ACTIVETAGINDICATORBAR_ALT1_PATCH N/A + +/* The alpha patch adds transparency for the status bar. + * You need to uncomment the corresponding line in config.mk to use the -lXrender library + * when including this patch. + * https://dwm.suckless.org/patches/alpha/ + */ +#define BAR_ALPHA_PATCH 0 + +/* This patch introduces alternative tags which can be switched on the fly for the + * sole purpose of providing visual aid. + * https://dwm.suckless.org/patches/alternativetags/ + */ +#define BAR_ALTERNATIVE_TAGS_PATCH 0 + +/* This patches provides the ability to use alternative text for tags which contain at + * least one window. + * https://dwm.suckless.org/patches/alttagsdecoration/ + */ +#define BAR_ALTTAGSDECORATION_PATCH 0 + +/* This patch enables dwm to manage external status bars such as lemonbar and polybar. + * dwm treats the external bar as it would its own, so all regular dwm commands such as + * togglebar affect the external bar in the same way. + * + * NB: Unless you want both anybar + dwm bar(s) then the recommendation is to disable all + * bar modules and have { 0 } in the barrules. + * + * https://dwm.suckless.org/patches/anybar/ + */ +#define BAR_ANYBAR_PATCH 0 + +/* This patch adds a border around the status bar(s) just like the border of client windows. + * https://codemadness.org/paste/dwm-border-bar.patch + */ +#define BAR_BORDER_PATCH 0 + +/* This patch centers the WM_NAME of the currently selected window on the status bar. + * This is compatible with the wintitle, bartabgroups, flexwintitle and awesomebar bar + * modules. + * https://dwm.suckless.org/patches/centeredwindowname/ + */ +#define BAR_CENTEREDWINDOWNAME_PATCH 0 + +/* Draws a dot indicator overlayed on each tag icon for each client. The selected client + * is drawn as a larger horizontal line. + * Set the tagindicatortype variable in config.h to INDICATOR_CLIENT_DOTS to enable this. + * https://dwm.suckless.org/patches/clientindicators/ + */ +#define BAR_CLIENTINDICATOR_PATCH N/A + +/* This patch enables color emoji in dwm by removing a workaround for a BadLength error + * in the Xft library when color glyphs are used. + * To enable this you will need an updated Xft library that can handle color glyphs otherwise + * dwm will crash on encountering such characters. Note that you will also need a font that + * provides color emojis for this to work. + */ +#define BAR_COLOR_EMOJI_PATCH 0 + +/* Updates the position of dmenu to match that of the bar. I.e. if topbar is 0 then dmenu + * will appear at the bottom and if 1 then dmenu will appear at the top. + * https://dwm.suckless.org/patches/dmenumatchtop + */ +#define BAR_DMENUMATCHTOP_PATCH 0 + +/* Originally this was the extrabar patch, but as the handling of extra bars is now built-in + * only the splitting of the status by a designated separator remains. As such this has been + * renamed to more accurately reflect what it does - creating an extra status. + * https://dwm.suckless.org/patches/extrabar/ + */ +#define BAR_EXTRASTATUS_PATCH 0 + +/* Adds EWMH support for _NET_NUMBER_OF_DESKTOPS, _NET_CURRENT_DESKTOP, _NET_DESKTOP_NAMES + * and _NET_DESKTOP_VIEWPORT, which allows for compatibility with other bars and programs + * that request workspace information. For example polybar's xworkspaces module. + * + * This patch also includes support for adding the _IS_FLOATING property for floating windows + * allowing for compositors to treat floating windows differently to tiled windows. + * + * E.g. this setting makes picom only render shadows for floating windows: + * + * shadow-exclude = [ "! _IS_FLOATING@:32c = 1" ]; + * + * https://github.com/bakkeby/dwm-flexipatch/issues/50 (_IS_FLOATING patch) + * https://dwm.suckless.org/patches/ewmhtags/ + */ +#define BAR_EWMHTAGS_PATCH 0 + +/* Allows the bar height to be explicitly set rather than being derived from font. + * https://dwm.suckless.org/patches/bar_height/ + */ +#define BAR_HEIGHT_PATCH 0 + +/* This patch prevents dwm from drawing tags with no clients (i.e. vacant) on the bar. + * https://dwm.suckless.org/patches/hide_vacant_tags/ + */ +#define BAR_HIDEVACANTTAGS_PATCH 0 + +/* With this patch dwm's built-in status bar is only shown when HOLDKEY is pressed + * and the bar will now overlay the display. + * http://dwm.suckless.org/patches/holdbar/ + */ +#define BAR_HOLDBAR_PATCH 0 + +/* Sometimes dwm crashes when it cannot render some glyphs in window titles (usually emoji). + * This patch is essentially a hack to ignore any errors when drawing text on the status bar. + * https://groups.google.com/forum/m/#!topic/wmii/7bncCahYIww + * https://docs.google.com/viewer?a=v&pid=forums&srcid=MDAwODA2MTg0MDQyMjE0OTgzMzMBMDQ3ODQzODkyMTU3NTAyMTMxNTYBX2RUMVNtOUtDQUFKATAuMQEBdjI&authuser=0 + */ +#define BAR_IGNORE_XFT_ERRORS_WHEN_DRAWING_TEXT_PATCH 0 + +/* This patch adds vertical and horizontal space between the statusbar and the edge of the screen. + * https://dwm.suckless.org/patches/barpadding/ + */ +#define BAR_PADDING_PATCH 0 + +/* This patch adds simple markup for status messages using pango markup. + * This depends on the pango library v1.44 or greater. + * You need to uncomment the corresponding lines in config.mk to use the pango libraries + * when including this patch. + * + * Note that the pango patch does not protect against the BadLength error from Xft + * when color glyphs are used, which means that dwm will crash if color emoji is used. + * + * If you need color emoji then you may want to install this patched library from the AUR: + * https://aur.archlinux.org/packages/libxft-bgra/ + * + * A long term fix for the libXft library is pending approval of this pull request: + * https://gitlab.freedesktop.org/xorg/lib/libxft/-/merge_requests/1 + * + * Also see: + * https://developer.gnome.org/pygtk/stable/pango-markup-language.html + * https://lists.suckless.org/hackers/2004/17285.html + * https://dwm.suckless.org/patches/pango/ + */ +#define BAR_PANGO_PATCH 0 + +/* This patch enables colored text in the status bar. It changes the way colors are defined + * in config.h allowing multiple color combinations for use in the status script. + * This patch is incompatible with and takes precedence over the status2d patch. + * https://dwm.suckless.org/patches/statuscolors/ + */ +#define BAR_STATUSCOLORS_PATCH 0 + +/* This patch adds configuration options for horizontal and vertical padding in the status bar. + * https://dwm.suckless.org/patches/statuspadding/ + */ +#define BAR_STATUSPADDING_PATCH 0 + +/* This patch adds the ability for dwm to read colors from the linux virtual console. + * /sys/module/vt/parameters/default_{red,grn,blu} + * Essentially this way the colors you use in your regular tty is "mirrored" to dwm. + * https://dwm.suckless.org/patches/vtcolors/ + */ +#define BAR_VTCOLORS_PATCH 0 + +/* This patch allows client windows to be hidden. This code was originally part of awesomebar, + * but has been separated out so that other bar modules can take advantage of it. + * Both awesomebar and bartabgroups patches depend on this patch and it will be auto-enabled + * during compile time if it is needed. Note that if using flexipatch-finalizer this must be + * explicitly enabled. + * https://github.com/bakkeby/patches/blob/master/dwm/dwm-barmodules-wintitleactions-6.2.diff + */ +#define BAR_WINTITLEACTIONS_PATCH BAR_AWESOMEBAR_PATCH || BAR_TABGROUPS_PATCH || BAR_FLEXWINTITLE_PATCH + +/*** + * Other patches + */ + +/* This patch allows windows to be resized with its aspect ratio remaining constant. + * https://dwm.suckless.org/patches/aspectresize/ + */ +#define ASPECTRESIZE_PATCH 0 + +/* This patch prevents the focus to drift from the active fullscreen client when + * using focusstack(). + * https://dwm.suckless.org/patches/alwaysfullscreen/ + */ +#define ALWAYSFULLSCREEN_PATCH 0 + +/* This patch adds new clients above the selected client, instead of always + * becoming the new master. This behaviour is known from Xmonad. + * This patch takes precedence over ATTACHASIDE_PATCH. + * https://dwm.suckless.org/patches/attachabove/ + */ +#define ATTACHABOVE_PATCH 0 + +/* This patch adds new clients on top of the stack. + * This patch takes precedence over ATTACHBELOW_PATCH. + * https://dwm.suckless.org/patches/attachaside/ + */ +#define ATTACHASIDE_PATCH 0 + +/* This patch adds new clients below the selected client. + * This patch takes precedence over ATTACHBOTTOM_PATCH. + * https://dwm.suckless.org/patches/attachbelow/ + */ +#define ATTACHBELOW_PATCH 0 + +/* This patch adds new clients at the bottom of the stack. + * https://dwm.suckless.org/patches/attachbottom/ + */ +#define ATTACHBOTTOM_PATCH 0 + +/* This patch will make dwm run "~/.local/share/dwm/autostart_blocking.sh" and + * "~/.local/share/dwm/autostart.sh &" before entering the handler loop. One or + * both of these files can be ommited. Note the path inside .local/share rather + * than the original ~/.dwm folder. + * https://dwm.suckless.org/patches/autostart/ + */ +#define AUTOSTART_PATCH 0 + +/* By default, windows that are not visible when requesting a resize/move will not + * get resized/moved. With this patch, they will. + * https://dwm.suckless.org/patches/autoresize/ + */ +#define AUTORESIZE_PATCH 0 + +/* This patch adds an iscentered rule to automatically center clients on the current monitor. + * This patch takes precedence over centeredwindowname and fancybar patches. + * https://dwm.suckless.org/patches/center/ + */ +#define CENTER_PATCH 0 + +/* A transient window is one that is meant to be short lived and is usually raised by a + * parent window. Such windows are typically dialog boxes and the like. + * It should be noted that in dwm transient windows are not subject to normal client rules + * and they are always floating by default. + * This patch centers transient windows on the screen like the center patch does. Note that + * the 6.2 center patch piggy-backed on the updatewindowtype function to ensure that all + * dialog boxes were centered, transient or not. This function was removed in relation to + * adding wintype as a client rule filter, hence this no longer works out of the box. This + * patch restores previous behaviour with the center patch. + */ +#define CENTER_TRANSIENT_WINDOWS_PATCH 0 + +/* As above, except that the transient window is centered within the position of the parent + * window, rather than at the center of the screen. This takes precedence over the above patch. + */ +#define CENTER_TRANSIENT_WINDOWS_BY_PARENT_PATCH 0 + +/* This patch provides the ability to assign different weights to clients in their + * respective stack in tiled layout. + * https://dwm.suckless.org/patches/cfacts/ + */ +#define CFACTS_PATCH 0 + +/* This patch allows color attributes to be set through the command line. + * https://dwm.suckless.org/patches/cmdcustomize/ + */ +#define CMDCUSTOMIZE_PATCH 0 + +/* This patch tweaks the tagging interface so that you can select multiple tags for tag + * or view by pressing all the right keys as a combo. For example to view tags 1 and 3, + * hold MOD and then press and hold 1 and 3 together. + * https://dwm.suckless.org/patches/combo/ + */ +#define COMBO_PATCH 0 + +/* Allow dwm to execute commands from autostart array in your config.h file. When dwm exits + * then all processes from autostart array will be killed. + * https://dwm.suckless.org/patches/cool_autostart/ + */ +#define COOL_AUTOSTART_PATCH 0 + +/* The cyclelayouts patch lets you cycle through all your layouts. + * https://dwm.suckless.org/patches/cyclelayouts/ + */ +#define CYCLELAYOUTS_PATCH 0 + +/* Make dwm respect _MOTIF_WM_HINTS property, and not draw borders around windows requesting + * for it. Some applications use this property to notify window managers to not draw window + * decorations. + * Not respecting this property leads to issues with applications that draw their own borders, + * like chromium (with "Use system title bar and borders" turned off) or vlc in fullscreen mode. + * https://dwm.suckless.org/patches/decoration_hints/ + */ +#define DECORATION_HINTS_PATCH 0 + +/* Similarly to the dragmfact patch this allows you to click and drag clients to change the + * cfact to adjust the client's size in the stack. This patch depends on the cfacts patch. + */ +#define DRAGCFACT_PATCH 0 + +/* This patch lets you resize the split in the tile layout (i.e. modify mfact) by holding + * the modkey and dragging the mouse. + * This patch can be a bit wonky with other layouts, but generally works. + * https://dwm.suckless.org/patches/dragmfact/ + */ +#define DRAGMFACT_PATCH 0 + +/* Simple dwmc client using a fork of fsignal to communicate with dwm. + * To use this either copy the patch/dwmc shell script to somewhere in your path or + * uncomment the following line in Makefile: + * #cp -f patch/dwmc ${DESTDIR}${PREFIX}/bin + * http://dwm.suckless.org/patches/dwmc/ + */ +#define DWMC_PATCH 0 + +/* This patch allows no tag at all to be selected. The result is that dwm will start with + * no tag selected and when you start a client with no tag rule and no tag selected then + * it will be opened on the first tag. + * https://dwm.suckless.org/patches/emptyview/ + */ +#define EMPTYVIEW_PATCH 0 + +/* This patch allows the user to change size and placement of floating windows using only the + * keyboard. It also allows for temporary vertical and horizontal extension of windows similar + * to other WMs fill command. + * https://dwm.suckless.org/patches/exresize/ + */ +#define EXRESIZE_PATCH 0 + +/* Only allow clients to "fullscreen" into the space currently given to them. + * As an example, this will allow you to view a fullscreen video in your browser on + * one half of the screen, while having the other half available for other tasks. + * This patch takes precedence over the fakefullscreen client patch below. + * https://dwm.suckless.org/patches/fakefullscreen/ + */ +#define FAKEFULLSCREEN_PATCH 0 + +/* Similarly to the fakefullscreen patch this patch only allows clients to "fullscreen" into + * the space currently given to them. + * The "twist" with this patch is that fake fullscreen can be toggled on a per client basis + * rather than applying to all clients globally. + * Also see the selectivefakefullscreen option that adds a rule option to enabled this on client + * startup. + */ +#define FAKEFULLSCREEN_CLIENT_PATCH 0 + +/* This patch adds a float rule allowing the size and position of floating windows to be specified + * It also allows the size and position of floating windows to be controlled similar to the + * exresize, moveresize, and moveplace patches. + * The size and position can be specified using absolute, relative or fixed co-ordinates and + * https://github.com/bakkeby/patches/wiki/floatpos/ + */ +#define FLOATPOS_PATCH 0 + +/* Add-on functionality for the above: make the float positions respect outer (vanity)gaps. */ +#define FLOATPOS_RESPECT_GAPS_PATCH 0 + +/* This patch provides the ability to focus the tag on the immediate left or right of the + * currently focused tag. It also allows to send the focused window either on the left or + * the right tag. + * http://dwm.suckless.org/patches/focusadjacenttag/ + */ +#define FOCUSADJACENTTAG_PATCH 0 + +/* Allows focusing on clients based on direction (up, down, left, right) instead of client order. + * https://github.com/bakkeby/patches/wiki/focusdir/ + */ +#define FOCUSDIR_PATCH 0 + +/* A simple patch that just puts focus back to the master client. + * https://dwm.suckless.org/patches/focusmaster/ + */ +#define FOCUSMASTER_PATCH 0 + +/* Switch focus only by mouse click and not sloppy (focus follows mouse pointer). + * https://dwm.suckless.org/patches/focusonclick/ + */ +#define FOCUSONCLICK_PATCH 0 + +/* Selects the next window having the urgent flag regardless of the tag it is on. + * The urgent flag can be artificially set with the following xdotool command on any window: + * xdotool selectwindow -- set_window --urgency 1 + * https://dwm.suckless.org/patches/focusurgent/ + */ +#define FOCUSURGENT_PATCH 0 + +/* By default, dwm responds to _NET_ACTIVE_WINDOW client messages by setting + * the urgency bit on the named window. This patch activates the window instead. + * https://dwm.suckless.org/patches/focusonnetactive/ + */ +#define FOCUSONNETACTIVE_PATCH 0 + +/* Send "fake signals" to dwm for handling, using xsetroot. This will not conflict with the + * status bar, which also is managed using xsetroot. + * Also see the dwmc patch, which takes precedence over this patch. + * https://dwm.suckless.org/patches/fsignal/ + */ +#define FSIGNAL_PATCH 0 + +/* Applies the monocle layout with the focused client on top and hides the bar. When pressed + * again it shows the bar and restores the layout that was active before going fullscreen. + * https://dwm.suckless.org/patches/fullscreen/ + */ +#define FULLSCREEN_PATCH 0 + +/* This patch provides a keybinding to rotate all clients in the currently selected + * area (master or stack) without affecting the other area. + * https://dwm.suckless.org/patches/inplacerotate/ + */ +#define INPLACEROTATE_PATCH 0 + +/* This patch lets you define custom insets from each edge of the screen. One use case would be + * to arrange space for an external bar. + * https://dwm.suckless.org/patches/insets/ + */ +#define INSETS_PATCH 0 + +/* This patch (v1.5.7) implements inter-process communication through a UNIX socket for dwm. This + * allows for the window manager to be queried for information, e.g. listen for events such as tag + * or layout changes, as well as send commands to control the window manager via other programs. + * + * You need to uncomment the corresponding lines in config.mk to use the -lyajl library + * when including this patch. + * This patch depends on the following additional library: + * - yajl + * + * https://github.com/mihirlad55/dwm-ipc + * https://dwm.suckless.org/patches/ipc/ + */ +#define IPC_PATCH 0 + +/* Adds rule option for clients to avoid accidental termination by killclient for sticky windows. + * https://dwm.suckless.org/patches/ispermanent/ + */ +#define ISPERMANENT_PATCH 0 + +/* This patch adds key modes (like in vim or emacs) where chains of keyboard shortcuts + * can be performed. + * https://dwm.suckless.org/patches/keymodes/ + */ +#define KEYMODES_PATCH 0 + +/* This patch adds a keybinding to kills all visible clients that are not selected. + * https://dwm.suckless.org/patches/killunsel/ + */ +#define KILLUNSEL_PATCH 0 + +/* By default in dwm it is possible to make an application fullscreen, then use + * the focusstack keybindings to focus on other windows beneath the current window. + * It is also possible to spawn new windows (e.g. a terminal) that end up getting + * focus while the previous window remains in fullscreen. This patch ensures that + * in such scenarios the previous window loses fullscreen. + * https://github.com/bakkeby/patches/blob/master/dwm/dwm-losefullscreen-6.2.diff + */ +#define LOSEFULLSCREEN_PATCH 0 + +/* This patch adds helper functions for maximizing, horizontally and vertically, floating + * windows using keybindings. + * https://dwm.suckless.org/patches/maximize/ + */ +#define MAXIMIZE_PATCH 0 + +/* Control Music Player Daemon via keybinds. + * You need to uncomment the corresponding line in config.mk to use the -lmpdclient library + * when including this patch. + * This patch depends on the following additional library: + * - libmpdclient + * https://dwm.suckless.org/patches/mpdcontrol/ + */ +#define MPDCONTROL_PATCH 0 + +/* Adds rules per monitor, e.g. have default layouts per monitor. + * The use case for this is if the second monitor is vertical (i.e. rotated) then + * you may want to use a different default layout for this monitor than what is + * used for the main monitor. E.g. normal vertical split for main monitor and + * horizontal split for the second. + */ +#define MONITOR_RULES_PATCH 0 + +/* Always display the the monocle-symbol as defined in config.h if the monocle-layout + * is activated. Do not display the number of open clients in the current tag. + * https://dwm.suckless.org/patches/monoclesymbol/ + */ +#define MONOCLESYMBOL_PATCH 0 + +/* Makes a window floating and 1/3rd the height and 1/3rd the width of the screen and is + * positioned in either the center or one of the 8 cardinal directions depending on which + * key is pressed. + * https://dwm.suckless.org/patches/moveplace/ + */ +#define MOVEPLACE_PATCH 0 + +/* This patch allows you to move and resize dwm's clients using keyboard bindings. + * https://dwm.suckless.org/patches/moveresize/ + */ +#define MOVERESIZE_PATCH 0 + +/* This patch allows you to move clients around in the stack and swap them with the master. + * https://dwm.suckless.org/patches/movestack/ + */ +#define MOVESTACK_PATCH 0 + +/* Adds support for the _NET_CLIENT_LIST_STACKING atom, needed by certain applications like the + * Zoom video conferencing application. + * https://github.com/bakkeby/patches/wiki/netclientliststacking/ + */ +#define NET_CLIENT_LIST_STACKING_PATCH 0 + +/* Removes the border when there is only one window visible. + * https://dwm.suckless.org/patches/noborder/ + */ +#define NOBORDER_PATCH 0 + +/* Enable modifying or removing dmenu in config.def.h which resulted previously in a + * compilation error because two lines of code hardcode dmenu into dwm. + * https://dwm.suckless.org/patches/nodmenu/ + */ +#define NODMENU_PATCH 0 + +/* This patch allows for toggleable client button bindings that have no modifiers. + * This can, for example, allow you to move or resize using the mouse alone without holding + * down a modifier key. This can be practical if you have extra buttons on your mouse. + * While you can use button bindings with no modifiers without this patch in a bare dwm, + * those buttons are then unavailable for use within the application itself so being able to + * toggle these on and off can be necessary in certain situations (e.g. being able to use + * back and forward buttons in a browser). + + * Example bindings: + * { ClkClientWin, 0, Button8, movemouse, {0} }, + * { ClkClientWin, 0, Button9, resizemouse, {0} }, + */ +#define NO_MOD_BUTTONS_PATCH 0 + +/* When terminals have transparency then their borders also become transparent. + * This patch ensures that borders have no transparency. Note that this patch is + * only relevant if you are not using the alpha patch. + * https://github.com/szatanjl/dwm/commit/1529909466206016f2101457bbf37c67195714c8 + * https://dwm.suckless.org/patches/alpha/dwm-fixborders-6.2.diff + */ +#define NO_TRANSPARENT_BORDERS_PATCH 0 + +/* Port of InstantVM's on_empty_keys functionality allowing keybindings that apply only when + * a tag is empty. An example use case is being able to launch applications with first hand + * keys like "f" to launch firefox. + * + * https://github.com/instantOS/instantWM/ + * https://github.com/bakkeby/dwm-flexipatch/issues/51 + */ +#define ON_EMPTY_KEYS_PATCH 0 + +/* Minor patch that prevents more than one rule being matched for a given client. */ +#define ONLY_ONE_RULE_MATCH_PATCH 0 + +/* This patch makes it so dwm will only exit via quit() if no windows are open. + * This is to prevent you accidentally losing all your work. + * https://dwm.suckless.org/patches/onlyquitonempty/ + */ +#define ONLYQUITONEMPTY_PATCH 0 + +/* The pertag patch adds nmaster, mfacts and layouts per tag rather than per + * monitor (default). + * https://dwm.suckless.org/patches/pertag/ + */ +#define PERTAG_PATCH 0 + +/* This controls whether or not to also store bar position on a per + * tag basis, or leave it as one bar per monitor. + */ +#define PERTAGBAR_PATCH 0 + +/* This patch lets you change the position of a client in the stack using the mouse. + * https://github.com/bakkeby/patches/wiki/placemouse + */ +#define PLACEMOUSE_PATCH 0 + +/* This patch provides a way to move clients up and down inside the client list. + * https://dwm.suckless.org/patches/push/ + */ +#define PUSH_PATCH 0 + +/* This patch provides a way to move clients up and down inside the client list, + * but does not push up or down into the master area (except that it does not take + * nmaster into account). + * This takes precedence over the push patch above. + * https://dwm.suckless.org/patches/push/ + */ +#define PUSH_NO_MASTER_PATCH 0 + +/* Shifts all clients per tag to leftmost unoccupied tags. + * + * For example, if clients A, B, C are tagged on tags 1, 5, 9 respectively, when + * this function is called, they will now be on 1, 2, and 3. The focused client + * will also remain focused. + * + * Clients on multiple tags will be treated as if they only were only on their + * leftmost tag, and will be reduced to one tag after the operation is complete. + * https://dwm.suckless.org/patches/reorganizetags/ + */ +#define REORGANIZETAGS_PATCH 0 + +/* By default, windows only resize from the bottom right corner. With this + * patch the mouse is warped to the nearest corner and you resize from there. + * https://dwm.suckless.org/patches/resizecorners/ + */ +#define RESIZECORNERS_PATCH 0 + +/* Practically the same as resizecorners, but the cursor does not warp to corners. + * This takes precedence over the resizecorners patch. + * https://github.com/bakkeby/patches/blob/master/dwm/dwm-resizepoint-6.2.diff + */ +#define RESIZEPOINT_PATCH 0 + +/* Adds a keyboard shortcut to restart dwm or alternatively by using kill -HUP dwmpid. + * Additionally dwm can quit cleanly by using kill -TERM dwmpid. + * https://dwm.suckless.org/patches/restartsig/ + */ +#define RESTARTSIG_PATCH 0 + +/* Adds rio-like drawing to resize the selected client. + * This depends on an external tool slop being installed. + * This patch was backported from instantWM. + * https://github.com/bakkeby/patches/blob/master/dwm/dwm-riodraw-6.2.diff + */ +#define RIODRAW_PATCH 0 + +/* This patch let's you rotate through the stack using keyboard shortcuts. + * https://dwm.suckless.org/patches/rotatestack/ + */ +#define ROTATESTACK_PATCH 0 + +/* This patch adds rounded corners to client windows in dwm. + * You need to uncomment the corresponding line in config.mk to use the -lXext library + * when including this patch. You will also want to set "borderpx = 0;" in your config.h. + * https://github.com/mitchweaver/suckless/blob/master/dwm/patches_mitch/mitch-06-rounded_corners-db6093f6ec1bb884f7540f2512935b5254750b30.patch + */ +#define ROUNDED_CORNERS_PATCH 0 + +/* This patch saves size and position of every floating window before it is forced + * into tiled mode. If the window is made floating again then the old dimensions + * will be restored. + * https://dwm.suckless.org/patches/save_floats/ + */ +#define SAVEFLOATS_PATCH 0 + +/* The scratchpad patch allows you to spawn or restore floating terminal windows. + * It is typically useful when one need to do some short typing. + * + * Note that this patch changes TAGMASK to make room for special scratchpad tags, + * so ~0 does more than select all tags with this patch. Code that relies on ~0 to + * represent all tags should use ~SPTAGMASK instead. + * + * Upgraded to Christian Tenllado's multiple scratchpad version. + * https://lists.suckless.org/hackers/2004/17205.html + * https://dwm.suckless.org/patches/scratchpads/ + */ +#define SCRATCHPADS_PATCH 0 + +/* Minor alteration of the above allowing clients to keep their size and position when shown */ +#define SCRATCHPADS_KEEP_POSITION_AND_SIZE_PATCH 0 + +/* This alternative patch enables a scratchpad feature in dwm similar to the scratchpad + * feature in i3wm. + * https://github.com/GasparVardanyan/dwm-scratchpad + */ +#define SCRATCHPAD_ALT_1_PATCH 0 + +/* As opposed to the original patch this only adds a rule option allowing fake fullscreen + * to be enabled for applications when they start. This is intended to be used in combination + * with the fakefullscreenclient patch and offers no practical functionality without it. + * https://dwm.suckless.org/patches/selectivefakefullscreen/ + */ +#define SELECTIVEFAKEFULLSCREEN_PATCH 0 + +/* Allows restarting dwm without the dependency of an external script. + * https://dwm.suckless.org/patches/selfrestart/ + */ +#define SELFRESTART_PATCH 0 + +/* This patch allow clients to keep focus when being sent to another monitor. + * https://github.com/bakkeby/patches/blob/master/dwm/dwm-sendmon_keepfocus-6.2.diff + */ +#define SENDMON_KEEPFOCUS_PATCH 0 + +/* This patch allows border pixels to be changed during runtime. + * https://dwm.suckless.org/patches/setborderpx/ + */ +#define SETBORDERPX_PATCH 0 + +/* This patch adds keybindings for left and right circular shift through tags. + * https://github.com/chau-bao-long/dotfiles/blob/master/suckless/dwm/shiftview.diff + */ +#define SHIFTVIEW_PATCH 0 + +/* This variant of the shiftview patch adds left and right circular shift through tags, + * but skips tags where there are no clients. + */ +#define SHIFTVIEW_CLIENTS_PATCH 0 + +/* This patch makes dwm obey even "soft" sizehints for new clients. Any window + * that requests a specific initial size will be floated and set to that size. + * Unlike with "fixed size" windows, you are able to resize and/or unfloat these + * windows freely - only the initial state is affected. + * This version of the patch is honestly of limited utility since there are many + * clients that will abuse it. + * https://dwm.suckless.org/patches/sizehints/ + */ +#define SIZEHINTS_PATCH 0 + +/* This patch makes dwm obey even "soft" sizehints for new clients. This ruled + * version is essentially the same patch except it obeys the "isfloating" rule + * if it is available in config.h for the given client. + * https://dwm.suckless.org/patches/sizehints/ + */ +#define SIZEHINTS_RULED_PATCH 0 + +/* In a multi-head setup monitor 0 is by default the primary screen, with the left and right + * screen being monitor 1 and 2 respectively. This patch sorts screens left to right (or + * top to bottom in a vertical layout) which aims to address some inconsistencies when it + * comes to focusmon, tagmon and similar functionality. + * https://www.mail-archive.com/hackers@suckless.org/msg09400.html + */ +#define SORTSCREENS_PATCH 0 + +/* Spawns programs from currently focused client's working directory. + * https://dwm.suckless.org/patches/spawn_cwd/ + */ +#define SPAWNCMD_PATCH 0 + +/* This patch provides comprehensive utilities for managing the client stack, providing + * keyboard shortcuts for focusing or placing a client at specific positions in the stack. + * Note that the default keybindings for this patch have been changed in dwm-flexipatch + * due to the many conflicts with other patches. As it provides similar functionality to the + * swapfocus patch it also uses the MOD+s shortcut to focus the previously selected client, + * thus note a conflict between these two patches. + * https://dwm.suckless.org/patches/stacker/ + */ +#define STACKER_PATCH 0 + +/* Steam, and steam windows (games), trigger a ConfigureNotify request every time the window + * gets focus. More so, the configure event passed along from Steam tends to have the wrong + * x and y co-ordinates which can make the window, if floating, jump around the screen. + * + * This patch works around this age-old issue by ignoring the x and y co-ordinates for + * ConfigureNotify requests relating to Steam windows. + * + * https://github.com/bakkeby/patches/wiki/steam + */ +#define STEAM_PATCH 0 + +/* Adds toggleable keyboard shortcut to make a client 'sticky', i.e. visible on all tags. + * https://dwm.suckless.org/patches/sticky/ + */ +#define STICKY_PATCH 0 + +/* This patch adds "window swallowing" to dwm as known from Plan 9's windowing system rio. + * Clients marked with isterminal in config.h swallow a window opened by any child process, + * e.g. running xclock in a terminal. Closing the xclock window restores the terminal window + * in the current position. + * + * This patch depends on the following additional libraries: + * - libxcb + * - Xlib-libxcb + * - xcb-res + * + * You need to uncomment the corresponding line in config.mk to use the above libraries when + * including this patch. + * + * https://dwm.suckless.org/patches/swallow/ + */ +#define SWALLOW_PATCH 0 + +/* This patch depends on the pertag patch and makes it possible to switch focus with a single + * shortcut (MOD+s) instead of having to think if you should use mod-j or mod-k for reaching + * the previously used window. + * https://dwm.suckless.org/patches/swapfocus/ + */ +#define SWAPFOCUS_PATCH 0 + +/* This patch allows swapping the contents of the currently selected tag with another tag using + * keyboard shortcuts. + * https://dwm.suckless.org/patches/swaptags/ + */ +#define SWAPTAGS_PATCH 0 + +/* Switch focus between the master and stack columns using a single keybinding. + * https://dwm.suckless.org/patches/switchcol/ + */ +#define SWITCHCOL_PATCH 0 + +/* By default dwm allow you to set application specific rules so that you can have your browser, + * for example, start up on tag 9 optionally on a given monitor when you open your browser it is + * then automatically moved to the configured tag, but you have to manually enable the tag to see + * the newly opened application. + * This patch adds an extra configuration option for individual rules where: + * 0 is default behaviour + * 1 automatically moves you to the tag of the newly opened application and + * 2 enables the tag of the newly opened application in addition to your existing enabled tags + * 3 as 1, but closing that window reverts the view back to what it was previously (*) + * 4 as 2, but closing that window reverts the view back to what it was previously (*) + * + * (*) except if the client has been moved between tags or to another monitor + * + * https://github.com/bakkeby/patches/blob/master/dwm/dwm-switchtag-6.2.diff + * Also see https://dwm.suckless.org/patches/switchtotag + */ +#define SWITCHTAG_PATCH 0 + +/* Adds keyboard shortcuts to move all (or only floating) windows from one tag to another. + * https://dwm.suckless.org/patches/tagall/ + */ +#define TAGALL_PATCH 0 + +/* This patch allows you to move all visible windows on a monitor to an adjacent monitor. + * https://github.com/bakkeby/patches/blob/master/dwm/dwm-tagallmon-6.2.diff + */ +#define TAGALLMON_PATCH 0 + +/* This patch makes new clients attach into the stack area when you toggle a new tag into + * view. This means your master area will remain unchanged when toggling views. + * The allmaster patch will cause all clients in the master area to be left alone. This patch + * takes precedence over the onemaster tagintostack patch. + * https://dwm.suckless.org/patches/tagintostack/ + */ +#define TAGINTOSTACK_ALLMASTER_PATCH 0 + +/* This patch makes new clients attach into the stack area when you toggle a new tag into + * view. This means your master area will remain unchanged when toggling views. + * The onemaster patch will cause the first client in the master area to be left alone. + * https://dwm.suckless.org/patches/tagintostack/ + */ +#define TAGINTOSTACK_ONEMASTER_PATCH 0 + +/* If you try to send a fullscreen window to an adjacent monitor using tagmon then + * the window is moved behind the scenes, but it remains in fullscreen on the original + * monitor until you exit fullscreen view (at which point it will appear on the adjacent + * monitor). This patch allows a fullscreen window to be moved to an adjacent monitor + * while remaining in fullscreen. + * https://github.com/bakkeby/patches/blob/master/dwm/dwm-tagmonfixfs-6.2.diff + */ +#define TAGMONFIXFS_PATCH 0 + +/* Add functions and keybindings to tag a window to a desired tag on the next (right) + * or previous (left) monitor from the currently selected monitor. + * https://dwm.suckless.org/patches/tagothermonitor/ + */ +#define TAGOTHERMONITOR_PATCH 0 + +/* This patch allows you to swap all visible windows on one monitor with those of an + * adjacent monitor. + * https://github.com/bakkeby/patches/blob/master/dwm/dwm-tagswapmon-6.2.diff + */ +#define TAGSWAPMON_PATCH 0 + +/* This patch allows you to toggle fullscreen on and off using a single shortcut key. + * https://github.com/bakkeby/patches/blob/master/dwm/dwm-togglefullscreen-6.2.diff + */ +#define TOGGLEFULLSCREEN_PATCH 0 + +/* Lets you transfer the currently focused client between the master and stack area + * while increasing or decreasing the master area (nmaster) accordingly. + * https://dwm.suckless.org/patches/transfer/ + */ +#define TRANSFER_PATCH 0 + +/* Lets you transfer all clients between the master and stack area + * while increasing or decreasing the master area (nmaster) accordingly. + * https://dwm.suckless.org/patches/transfer/ + */ +#define TRANSFER_ALL_PATCH 0 + +/* This patch resets isfloating on any visible windows that have it set. + * Optionally also applies a layout. + * https://dwm.suckless.org/patches/unfloatvisible/ + */ +#define UNFLOATVISIBLE_PATCH 0 + +/* This patch adds configurable gaps between windows differentiating between outer, inner, + * horizontal and vertical gaps. + * https://github.com/bakkeby/patches/blob/master/dwm/dwm-vanitygaps-6.2.diff + * https://github.com/bakkeby/patches/blob/master/dwm/dwm-cfacts-vanitygaps-6.2.diff + */ +#define VANITYGAPS_PATCH 0 + +/* This patch adds outer gaps for the monocle layout. + * Most gaps patches tries to avoid gaps on the monocle layout, as it is often used as a + * fullscreen mode, hence this is enabled separately from the main vanitygaps patch. + */ +#define VANITYGAPS_MONOCLE_PATCH 0 + +/* Follow a window to the tag it is being moved to. + * https://dwm.suckless.org/patches/viewontag/ + */ +#define VIEWONTAG_PATCH 0 + +/* By default tags can be changed using MOD+ while MOD+Tab toggles between the current and + * the previous tag. This patch changes this so that if you hit MOD+ for the tag you are + * currently on, then it works the same as MOD+Tab and switches back to the previous tag. + * Idea ref. + * https://www.reddit.com/r/suckless/comments/ik27vd/key_toggle_between_next_and_previous_tag_dwm/ + */ +#define VIEW_SAME_TAG_GIVES_PREVIOUS_TAG_PATCH 0 + +/* This patch warps the mouse cursor to the center of the currently focused window or screen + * when the mouse cursor is (a) on a different screen or (b) on top of a different window. + * https://dwm.suckless.org/patches/warp/ + */ +#define WARP_PATCH 0 + +/* Sometimes a single application opens different windows depending on the task + * at hand and this is often reflected in the WM_WINDOW_ROLE(STRING) x property. + * This patch adds the role field to the rule configuration so that one can + * differentiate between, say, Firefox "browser" vs "Preferences" vs "Manager" + * or Google-chrome "browser" vs "pop-up". + * https://github.com/bakkeby/patches/blob/master/dwm/dwm-windowrolerule-6.2.diff + */ +#define WINDOWROLERULE_PATCH 0 + +/* The winview patch allows switching the view to that of a given client from the all-window + * view (Mod-0) using a keyboard shortcut. + * http://dwm.suckless.org/patches/winview/ + */ +#define WINVIEW_PATCH 0 + +/* Allows dwm to read colors from xrdb (.Xresources) during runtime. Compatible with + * the float border color, awesomebar, urgentborder and titlecolor patches. + * https://dwm.suckless.org/patches/xrdb/ + */ +#define XRDB_PATCH 0 + +/* Simple patch that allows floating windows to be zoomed into the master stack position. + * https://www.reddit.com/r/suckless/comments/ie5fe3/zoomfloating_my_own_simple_original_patch/ + */ +#define ZOOMFLOATING_PATCH 0 + +/* The zoomswap patch allows a master and a stack window to swap places + * rather than every window on the screen changing position. + * https://dwm.suckless.org/patches/zoomswap/ + */ +#define ZOOMSWAP_PATCH 0 + +/** + * Layouts + */ + +/* Bottomstack layout. + * https://dwm.suckless.org/patches/bottomstack/ + */ +#define BSTACK_LAYOUT 0 + +/* Bottomstack horizontal layout. + * https://dwm.suckless.org/patches/bottomstack/ + */ +#define BSTACKHORIZ_LAYOUT 0 + +/* Centered master layout. + * https://dwm.suckless.org/patches/centeredmaster/ + */ +#define CENTEREDMASTER_LAYOUT 0 + +/* Centered floating master layout. + * https://dwm.suckless.org/patches/centeredmaster/ + */ +#define CENTEREDFLOATINGMASTER_LAYOUT 0 + +/* Same as the default tile layout except clients in the master area are arranged in + * columns (i.e. left to right). + * https://dwm.suckless.org/patches/columns/ + */ +#define COLUMNS_LAYOUT 0 + +/* Deck layout. + * https://dwm.suckless.org/patches/deck/ + */ +#define DECK_LAYOUT 0 + +/* Fibonacci dwindle layout. + * https://dwm.suckless.org/patches/fibonacci/ + */ +#define FIBONACCI_DWINDLE_LAYOUT 0 + +/* Fibonacci spiral layout. + * https://dwm.suckless.org/patches/fibonacci/ + */ +#define FIBONACCI_SPIRAL_LAYOUT 0 + +/* Flextile deluxe layout. + * A revamped, more flexible, and over-the-top version of the original flextile layout. + * https://dwm.suckless.org/patches/flextile/ (original) + */ +#define FLEXTILE_DELUXE_LAYOUT 0 + +/* Gappless grid layout. + * https://dwm.suckless.org/patches/gaplessgrid/ + */ +#define GAPPLESSGRID_LAYOUT 0 + +/* Gridmode (grid) layout. + * https://dwm.suckless.org/patches/gridmode/ + */ +#define GRIDMODE_LAYOUT 0 + +/* Horizontal grid (horizgrid) layout. + * https://dwm.suckless.org/patches/horizgrid/ + */ +#define HORIZGRID_LAYOUT 0 + +/* Grid layout where nmaster controls the number of rows. + * https://dwm.suckless.org/patches/nrowgrid/ + */ +#define NROWGRID_LAYOUT 0 + +/* The default tile layout. + * This can be optionally disabled in favour of other layouts. + */ +#define TILE_LAYOUT 1 + +/* Monocle layout (default). + * This can be optionally disabled in favour of other layouts. + */ +#define MONOCLE_LAYOUT 1 diff --git a/suckless/dwm/patches/dwm-6.0-winview.diff b/suckless/dwm/patches/dwm-6.0-winview.diff deleted file mode 100644 index 1b796b53..00000000 --- a/suckless/dwm/patches/dwm-6.0-winview.diff +++ /dev/null @@ -1,65 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index 77ff358..3ba0efe 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -84,6 +84,7 @@ static Key keys[] = { - TAGKEYS( XK_8, 7) - TAGKEYS( XK_9, 8) - { MODKEY|ShiftMask, XK_q, quit, {0} }, -+ { MODKEY, XK_o, winview, {0} }, - }; - - /* button definitions */ -diff --git a/dwm.1 b/dwm.1 -index 5268a06..1188c82 100644 ---- a/dwm.1 -+++ b/dwm.1 -@@ -104,6 +104,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 1d78655..abf944c 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -247,6 +247,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); -@@ -2080,6 +2081,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/suckless/dwm/patches/dwm-actualfullscreen-20191112-cb3f58a.diff b/suckless/dwm/patches/dwm-actualfullscreen-20191112-cb3f58a.diff deleted file mode 100644 index 21eea19e..00000000 --- a/suckless/dwm/patches/dwm-actualfullscreen-20191112-cb3f58a.diff +++ /dev/null @@ -1,53 +0,0 @@ -From 3a16816a6f5d38014c2a06ce395873c545c8789a Mon Sep 17 00:00:00 2001 -From: Soenke Lambert -Date: Tue, 12 Nov 2019 10:44:02 +0100 -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.c | 8 ++++++++ - 2 files changed, 9 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.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.17.1 - diff --git a/suckless/dwm/patches/dwm-alttagsdecoration-2020010304-cb3f58a.diff b/suckless/dwm/patches/dwm-alttagsdecoration-2020010304-cb3f58a.diff deleted file mode 100644 index fcbc1ef1..00000000 --- a/suckless/dwm/patches/dwm-alttagsdecoration-2020010304-cb3f58a.diff +++ /dev/null @@ -1,67 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index 1c0b587..d4b11fc 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -20,6 +20,7 @@ static const char *colors[][3] = { - - /* tagging */ - static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; -+static const char *alttags[] = { "<01>", "<02>", "<03>", "<04>", "<05>" }; - - static const Rule rules[] = { - /* xprop(1): -diff --git a/dwm.c b/dwm.c -index 4465af1..a394159 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -416,7 +416,7 @@ attachstack(Client *c) - void - buttonpress(XEvent *e) - { -- unsigned int i, x, click; -+ unsigned int i, x, click, occ; - Arg arg = {0}; - Client *c; - Monitor *m; -@@ -430,9 +430,13 @@ buttonpress(XEvent *e) - focus(NULL); - } - if (ev->window == selmon->barwin) { -- i = x = 0; -+ i = x = occ = 0; -+ /* Bitmask of occupied tags */ -+ for (c = m->clients; c; c = c->next) -+ occ |= c->tags; -+ - do -- x += TEXTW(tags[i]); -+ x += TEXTW(occ & 1 << i ? alttags[i] : tags[i]); - while (ev->x >= x && ++i < LENGTH(tags)); - if (i < LENGTH(tags)) { - click = ClkTagBar; -@@ -699,6 +703,7 @@ drawbar(Monitor *m) - int boxs = drw->fonts->h / 9; - int boxw = drw->fonts->h / 6 + 2; - unsigned int i, occ = 0, urg = 0; -+ const char *tagtext; - Client *c; - - /* draw status first so it can be overdrawn by tags later */ -@@ -715,13 +720,10 @@ 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_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); -+ tagtext = occ & 1 << i ? alttags[i] : tags[i]; -+ w = TEXTW(tagtext); -+ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); -+ drw_text(drw, x, 0, w, bh, lrpad / 2, tagtext, urg & 1 << i); - x += w; - } - w = blw = TEXTW(m->ltsymbol); diff --git a/suckless/dwm/patches/dwm-alwayscenter-20200625-f04cac6.diff b/suckless/dwm/patches/dwm-alwayscenter-20200625-f04cac6.diff deleted file mode 100644 index 03ea9ef2..00000000 --- a/suckless/dwm/patches/dwm-alwayscenter-20200625-f04cac6.diff +++ /dev/null @@ -1,12 +0,0 @@ -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/suckless/dwm/patches/dwm-barpadding-20200720-bb2e722.diff b/suckless/dwm/patches/dwm-barpadding-20200720-bb2e722.diff deleted file mode 100644 index 35f490a2..00000000 --- a/suckless/dwm/patches/dwm-barpadding-20200720-bb2e722.diff +++ /dev/null @@ -1,124 +0,0 @@ -From 2f6da65e84288941babde413b9c3f4a619f853a1 Mon Sep 17 00:00:00 2001 -From: Pavel Oborin -Date: Mon, 20 Jul 2020 21:42:43 +0300 -Subject: [PATCH] Fixed drawbar - ---- - config.def.h | 2 ++ - dwm.c | 26 ++++++++++++++++---------- - 2 files changed, 18 insertions(+), 10 deletions(-) - -diff --git a/config.def.h b/config.def.h -index 1c0b587..867312f 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 9fd0286..ec9c293 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); -@@ -1548,6 +1550,9 @@ setup(void) - lrpad = drw->fonts->h; - bh = drw->fonts->h + 2; - updategeom(); -+ sp = sidepad; -+ vp = (topbar == 1) ? vertpad : - vertpad; -+ - /* init atoms */ - utf8string = XInternAtom(dpy, "UTF8_STRING", False); - wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); -@@ -1574,6 +1579,7 @@ setup(void) - /* init bars */ - updatebars(); - updatestatus(); -+ updatebarpos(selmon); - /* supporting window for NetWMCheck */ - wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0); - XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32, -@@ -1704,7 +1710,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 +1820,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 +1835,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.27.0 - diff --git a/suckless/dwm/patches/dwm-centeredmaster-6.1.diff b/suckless/dwm/patches/dwm-centeredmaster-6.1.diff deleted file mode 100644 index 69268927..00000000 --- a/suckless/dwm/patches/dwm-centeredmaster-6.1.diff +++ /dev/null @@ -1,142 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index 7054c06..527b214 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -39,6 +39,8 @@ static const Layout layouts[] = { - { "[]=", tile }, /* first entry is default */ - { "><>", NULL }, /* no layout function means floating behavior */ - { "[M]", monocle }, -+ { "|M|", centeredmaster }, -+ { ">M>", centeredfloatingmaster }, - }; - - /* key definitions */ -@@ -74,6 +76,8 @@ 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_u, setlayout, {.v = &layouts[3]} }, -+ { MODKEY, XK_o, setlayout, {.v = &layouts[4]} }, - { 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 0362114..1e81412 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -233,6 +233,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 centeredmaster(Monitor *m); -+static void centeredfloatingmaster(Monitor *m); - - /* variables */ - static const char broken[] = "broken"; -@@ -2139,3 +2141,106 @@ main(int argc, char *argv[]) - XCloseDisplay(dpy); - return EXIT_SUCCESS; - } -+ -+void -+centeredmaster(Monitor *m) -+{ -+ unsigned int i, n, h, mw, mx, my, oty, ety, tw; -+ Client *c; -+ -+ /* count number of clients in the selected monitor */ -+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); -+ if (n == 0) -+ return; -+ -+ /* initialize areas */ -+ mw = m->ww; -+ mx = 0; -+ my = 0; -+ tw = mw; -+ -+ if (n > m->nmaster) { -+ /* go mfact box in the center if more than nmaster clients */ -+ mw = m->nmaster ? m->ww * m->mfact : 0; -+ tw = m->ww - mw; -+ -+ if (n - m->nmaster > 1) { -+ /* only one client */ -+ mx = (m->ww - mw) / 2; -+ tw = (m->ww - mw) / 2; -+ } -+ } -+ -+ oty = 0; -+ ety = 0; -+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) -+ if (i < m->nmaster) { -+ /* nmaster clients are stacked vertically, in the center -+ * of the screen */ -+ h = (m->wh - my) / (MIN(n, m->nmaster) - i); -+ resize(c, m->wx + mx, m->wy + my, mw - (2*c->bw), -+ h - (2*c->bw), 0); -+ my += HEIGHT(c); -+ } else { -+ /* stack clients are stacked vertically */ -+ if ((i - m->nmaster) % 2 ) { -+ h = (m->wh - ety) / ( (1 + n - i) / 2); -+ resize(c, m->wx, m->wy + ety, tw - (2*c->bw), -+ h - (2*c->bw), 0); -+ ety += HEIGHT(c); -+ } else { -+ h = (m->wh - oty) / ((1 + n - i) / 2); -+ resize(c, m->wx + mx + mw, m->wy + oty, -+ tw - (2*c->bw), h - (2*c->bw), 0); -+ oty += HEIGHT(c); -+ } -+ } -+} -+ -+void -+centeredfloatingmaster(Monitor *m) -+{ -+ unsigned int i, n, w, mh, mw, mx, mxo, my, myo, tx; -+ Client *c; -+ -+ /* count number of clients in the selected monitor */ -+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); -+ if (n == 0) -+ return; -+ -+ /* initialize nmaster area */ -+ if (n > m->nmaster) { -+ /* go mfact box in the center if more than nmaster clients */ -+ if (m->ww > m->wh) { -+ mw = m->nmaster ? m->ww * m->mfact : 0; -+ mh = m->nmaster ? m->wh * 0.9 : 0; -+ } else { -+ mh = m->nmaster ? m->wh * m->mfact : 0; -+ mw = m->nmaster ? m->ww * 0.9 : 0; -+ } -+ mx = mxo = (m->ww - mw) / 2; -+ my = myo = (m->wh - mh) / 2; -+ } else { -+ /* go fullscreen if all clients are in the master area */ -+ mh = m->wh; -+ mw = m->ww; -+ mx = mxo = 0; -+ my = myo = 0; -+ } -+ -+ for(i = tx = 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 */ -+ w = (mw + mxo - mx) / (MIN(n, m->nmaster) - i); -+ resize(c, m->wx + mx, m->wy + my, w - (2*c->bw), -+ mh - (2*c->bw), 0); -+ mx += WIDTH(c); -+ } else { -+ /* stack clients are stacked horizontally */ -+ w = (m->ww - tx) / (n - i); -+ resize(c, m->wx + tx, m->wy, w - (2*c->bw), -+ m->wh - (2*c->bw), 0); -+ tx += WIDTH(c); -+ } -+} diff --git a/suckless/dwm/patches/dwm-cfacts-20200913-61bb8b2.diff b/suckless/dwm/patches/dwm-cfacts-20200913-61bb8b2.diff deleted file mode 100644 index bb70e138..00000000 --- a/suckless/dwm/patches/dwm-cfacts-20200913-61bb8b2.diff +++ /dev/null @@ -1,117 +0,0 @@ -From c32a879432573d71dec7fcb4bf68927d2f4cdf10 Mon Sep 17 00:00:00 2001 -From: iofq -Date: Sat, 12 Sep 2020 22:28:09 -0500 -Subject: [PATCH] Fixed 'cfacts' patch failure due to upstream commit - 'f09418bbb...' - ---- - config.def.h | 3 +++ - dwm.c | 34 +++++++++++++++++++++++++++++++--- - 2 files changed, 34 insertions(+), 3 deletions(-) - -diff --git a/config.def.h b/config.def.h -index 1c0b587..83910c1 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -70,6 +70,9 @@ static 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, XK_Tab, view, {0} }, - { MODKEY|ShiftMask, XK_c, killclient, {0} }, -diff --git a/dwm.c b/dwm.c -index 664c527..5233229 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; -@@ -201,6 +202,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); -@@ -1030,6 +1032,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))) { -@@ -1512,6 +1515,23 @@ 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) -@@ -1675,9 +1695,15 @@ void - tile(Monitor *m) - { - unsigned int i, n, h, mw, my, ty; -+ float mfacts = 0, sfacts = 0; - Client *c; - -- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); -+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { -+ if (n < m->nmaster) -+ mfacts += c->cfact; -+ else -+ sfacts += c->cfact; -+ } - if (n == 0) - return; - -@@ -1687,15 +1713,17 @@ tile(Monitor *m) - 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); -+ h = (m->wh - my) * (c->cfact / mfacts); - 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); -+ mfacts -= c->cfact; - } else { -- h = (m->wh - ty) / (n - i); -+ h = (m->wh - ty) * (c->cfact / sfacts); - 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); -+ sfacts -= c->cfact; - } - } - --- -2.28.0 - diff --git a/suckless/dwm/patches/dwm-cfacts_centeredmaster-6.2.diff b/suckless/dwm/patches/dwm-cfacts_centeredmaster-6.2.diff deleted file mode 100644 index 9a00b08e..00000000 --- a/suckless/dwm/patches/dwm-cfacts_centeredmaster-6.2.diff +++ /dev/null @@ -1,180 +0,0 @@ -diff -up a/config.def.h b/config.def.h ---- a/config.def.h 2019-06-05 02:24:05.503321320 +0200 -+++ b/config.def.h 2019-06-05 10:46:48.099997829 +0200 -@@ -41,6 +41,8 @@ static const Layout layouts[] = { - { "[]=", tile }, /* first entry is default */ - { "><>", NULL }, /* no layout function means floating behavior */ - { "[M]", monocle }, -+ { "|M|", centeredmaster }, -+ { ">M>", centeredfloatingmaster }, - }; - - /* key definitions */ -@@ -79,6 +81,8 @@ 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_u, setlayout, {.v = &layouts[3]} }, -+ { MODKEY, XK_o, setlayout, {.v = &layouts[4]} }, - { MODKEY, XK_space, setlayout, {0} }, - { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, - { MODKEY, XK_0, view, {.ui = ~0 } }, -Only in a: config.def.h.orig -Only in b: dwm-bottomstack-20160719-56a31dc.diff -diff -up a/dwm.c b/dwm.c ---- a/dwm.c 2019-06-05 02:25:40.169986187 +0200 -+++ b/dwm.c 2019-06-05 10:48:42.443328992 +0200 -@@ -235,6 +235,8 @@ static int xerror(Display *dpy, XErrorEv - static int xerrordummy(Display *dpy, XErrorEvent *ee); - static int xerrorstart(Display *dpy, XErrorEvent *ee); - static void zoom(const Arg *arg); -+static void centeredmaster(Monitor *m); -+static void centeredfloatingmaster(Monitor *m); - - /* variables */ - static const char broken[] = "broken"; -@@ -2175,3 +2177,144 @@ main(int argc, char *argv[]) - XCloseDisplay(dpy); - return EXIT_SUCCESS; - } -+ -+void -+centeredmaster(Monitor *m) -+{ -+ unsigned int i, n, h, mw, mx, my, oty, ety, tw; -+ float mfacts = 0, lfacts = 0, rfacts = 0; -+ Client *c; -+ -+ /* count number of clients in the selected monitor */ -+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { -+ if (n < m->nmaster) -+ mfacts += c->cfact; -+ else if ((n - m->nmaster) % 2) -+ lfacts += c->cfact; -+ else -+ rfacts += c->cfact; -+ } -+ if (n == 0) -+ return; -+ if(n == 1){ -+ c = nexttiled(m->clients); -+ resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0); -+ return; -+ } -+ -+ /* initialize areas */ -+ mw = m->ww; -+ mx = 0; -+ my = 0; -+ tw = mw; -+ -+ if (n > m->nmaster) { -+ /* go mfact box in the center if more than nmaster clients */ -+ mw = m->nmaster ? m->ww * m->mfact : 0; -+ tw = m->ww - mw; -+ -+ if (n - m->nmaster > 1) { -+ /* only one client */ -+ mx = (m->ww - mw) / 2; -+ tw = (m->ww - mw) / 2; -+ } -+ } -+ -+ oty = 0; -+ ety = 0; -+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) -+ if (i < m->nmaster) { -+ /* nmaster clients are stacked vertically, in the center -+ * of the screen */ -+ h = (m->wh - my) * (c->cfact / mfacts); -+ resize(c, m->wx + mx, m->wy + my, mw - 2*c->bw, -+ h - 2*c->bw, 0); -+ if(my + HEIGHT(c) < m->mh) -+ my += HEIGHT(c); -+ mfacts -= c->cfact; -+ } else { -+ /* stack clients are stacked vertically */ -+ if ((i - m->nmaster) % 2) { -+ h = (m->wh - ety) * (c->cfact / lfacts); -+ if(m->nmaster == 0) -+ resize(c, m->wx, m->wy + ety, tw - 2*c->bw, -+ h - 2*c->bw, 0); -+ else -+ resize(c, m->wx, m->wy + ety, tw - 2*c->bw, -+ h - 2*c->bw, 0); -+ if(ety + HEIGHT(c) < m->mh) -+ ety += HEIGHT(c); -+ lfacts -= c->cfact; -+ } else { -+ h = (m->wh - oty) * (c->cfact / rfacts); -+ resize(c, m->wx + mx + mw, m->wy + oty, -+ tw - 2*c->bw, h - 2*c->bw, 0); -+ if(oty + HEIGHT(c) < m->mh) -+ oty += HEIGHT(c); -+ rfacts -= c->cfact; -+ } -+ } -+} -+ -+void -+centeredfloatingmaster(Monitor *m) -+{ -+ unsigned int i, n, w, mh, mw, mx, mxo, my, myo, tx; -+ float mfacts = 0, sfacts = 0; -+ Client *c; -+ -+ /* count number of clients in the selected monitor */ -+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { -+ if (n < m->nmaster) -+ mfacts += c->cfact; -+ else -+ sfacts += c->cfact; -+ } -+ if (n == 0) -+ return; -+ if(n == 1){ -+ c = nexttiled(m->clients); -+ resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0); -+ return; -+ } -+ -+ /* initialize nmaster area */ -+ if (n > m->nmaster) { -+ /* go mfact box in the center if more than nmaster clients */ -+ if (m->ww > m->wh) { -+ mw = m->nmaster ? m->ww * m->mfact : 0; -+ mh = m->nmaster ? m->wh * 0.9 : 0; -+ } else { -+ mh = m->nmaster ? m->wh * m->mfact : 0; -+ mw = m->nmaster ? m->ww * 0.9 : 0; -+ } -+ mx = mxo = (m->ww - mw) / 2; -+ my = myo = (m->wh - mh) / 2; -+ } else { -+ /* go fullscreen if all clients are in the master area */ -+ mh = m->wh; -+ mw = m->ww; -+ mx = mxo = 0; -+ my = myo = 0; -+ } -+ -+ for(i = tx = 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 */ -+ w = (mw + mxo - mx) * (c->cfact / mfacts); -+ resize(c, m->wx + mx, m->wy + my, w - 2*c->bw, -+ mh - 2*c->bw, 0); -+ if(mx + WIDTH(c) < m->mw) -+ mx += WIDTH(c); -+ mfacts -= c->cfact; -+ } else { -+ /* stack clients are stacked horizontally */ -+ w = (m->ww - tx) * (c->cfact / sfacts); -+ resize(c, m->wx + tx, m->wy, w - 2*c->bw, -+ m->wh - 2*c->bw, 0); -+ if(tx + WIDTH(c) < m->mw) -+ tx += WIDTH(c); -+ sfacts -= c->cfact; -+ } -+} diff --git a/suckless/dwm/patches/dwm-colorbar-6.2.diff b/suckless/dwm/patches/dwm-colorbar-6.2.diff deleted file mode 100644 index 91c067da..00000000 --- a/suckless/dwm/patches/dwm-colorbar-6.2.diff +++ /dev/null @@ -1,68 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index 1c0b587..a516645 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 */ -diff --git a/dwm.c b/dwm.c -index 4465af1..0d1d2f7 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 */ -@@ -703,7 +703,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]); - sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ - drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0); - } -@@ -716,7 +716,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, -@@ -725,17 +725,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 - sw - 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); - } - } diff --git a/suckless/dwm/patches/dwm-cyclelayouts-20180524-6.2.diff b/suckless/dwm/patches/dwm-cyclelayouts-20180524-6.2.diff deleted file mode 100644 index 8079028b..00000000 --- a/suckless/dwm/patches/dwm-cyclelayouts-20180524-6.2.diff +++ /dev/null @@ -1,93 +0,0 @@ -From a09e766a4342f580582082a92b2de65f33208eb4 Mon Sep 17 00:00:00 2001 -From: Christopher Drelich -Date: Thu, 24 May 2018 00:56:56 -0400 -Subject: [PATCH] Function to cycle through available layouts. - -MOD-CTRL-, and MOD-CTRL-. -cycle backwards and forwards through available layouts. -Probably only useful if you have a lot of additional layouts. -The NULL, NULL layout should always be the last layout in your list, -in order to guarantee consistent behavior. ---- - config.def.h | 3 +++ - dwm.1 | 6 ++++++ - dwm.c | 18 ++++++++++++++++++ - 3 files changed, 27 insertions(+) - -diff --git a/config.def.h b/config.def.h -index a9ac303..153b880 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -41,6 +41,7 @@ static const Layout layouts[] = { - { "[]=", tile }, /* first entry is default */ - { "><>", NULL }, /* no layout function means floating behavior */ - { "[M]", monocle }, -+ { NULL, NULL }, - }; - - /* key definitions */ -@@ -76,6 +77,8 @@ 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|ControlMask, XK_comma, cyclelayout, {.i = -1 } }, -+ { MODKEY|ControlMask, XK_period, cyclelayout, {.i = +1 } }, - { MODKEY, XK_space, setlayout, {0} }, - { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, - { MODKEY, XK_0, view, {.ui = ~0 } }, -diff --git a/dwm.1 b/dwm.1 -index 13b3729..165891b 100644 ---- a/dwm.1 -+++ b/dwm.1 -@@ -92,6 +92,12 @@ Sets monocle layout. - .B Mod1\-space - Toggles between current and previous layout. - .TP -+.B Mod1\-Control\-, -+Cycles backwards in layout list. -+.TP -+.B Mod1\-Control\-. -+Cycles forwards in layout list. -+.TP - .B Mod1\-j - Focus next window. - .TP -diff --git a/dwm.c b/dwm.c -index bb95e26..db73000 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -157,6 +157,7 @@ static void configure(Client *c); - static void configurenotify(XEvent *e); - static void configurerequest(XEvent *e); - static Monitor *createmon(void); -+static void cyclelayout(const Arg *arg); - static void destroynotify(XEvent *e); - static void detach(Client *c); - static void detachstack(Client *c); -@@ -645,6 +646,23 @@ createmon(void) - } - - void -+cyclelayout(const Arg *arg) { -+ Layout *l; -+ for(l = (Layout *)layouts; l != selmon->lt[selmon->sellt]; l++); -+ if(arg->i > 0) { -+ if(l->symbol && (l + 1)->symbol) -+ setlayout(&((Arg) { .v = (l + 1) })); -+ else -+ setlayout(&((Arg) { .v = layouts })); -+ } else { -+ if(l != layouts && (l - 1)->symbol) -+ setlayout(&((Arg) { .v = (l - 1) })); -+ else -+ setlayout(&((Arg) { .v = &layouts[LENGTH(layouts) - 2] })); -+ } -+} -+ -+void - destroynotify(XEvent *e) - { - Client *c; --- -2.7.4 - diff --git a/suckless/dwm/patches/dwm-deck-6.0.diff b/suckless/dwm/patches/dwm-deck-6.0.diff deleted file mode 100644 index 39ec2ad9..00000000 --- a/suckless/dwm/patches/dwm-deck-6.0.diff +++ /dev/null @@ -1,90 +0,0 @@ -From cb3cac91db32403bb581aecbc2957b00bb49c898 Mon Sep 17 00:00:00 2001 -From: aleks -Date: Mon, 6 May 2019 16:34:58 +0200 -Subject: [PATCH] Add deck-layout - -deck is a dwm-layout which is inspired by the TTWM window manager. -It applies the monocle-layout to the clients in the stack. -The master-client is still visible. The stacked clients are like -a deck of cards, hence the name. - -The vanilla patch doesn't work properly with patches which add gaps. -This means that when the deck-layout is activated gaps are omitted. -To make it work with the tilegap-patch apply the dwm-deck-tilegap patch -on top of the dwm-deck patch. - -The vanilla patch doesn't respect the master-area which is defined by -the rmaster-patch. To make it work with the rmaster-patch apply the -dwm-deck-rmaster patch on top of the dwm-deck patch. ---- - config.def.h | 2 ++ - dwm.c | 26 ++++++++++++++++++++++++++ - 2 files changed, 28 insertions(+) - -diff --git a/config.def.h b/config.def.h -index 77ff358..55d8a07 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -32,6 +32,7 @@ static const Layout layouts[] = { - { "[]=", tile }, /* first entry is default */ - { "><>", NULL }, /* no layout function means floating behavior */ - { "[M]", monocle }, -+ { "[D]", deck }, - }; - - /* key definitions */ -@@ -66,6 +67,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_c, 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 1d78655..356ab44 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -171,6 +171,7 @@ static void configure(Client *c); - static void configurenotify(XEvent *e); - static void configurerequest(XEvent *e); - static Monitor *createmon(void); -+static void deck(Monitor *m); - static void destroynotify(XEvent *e); - static void detach(Client *c); - static void detachstack(Client *c); -@@ -669,6 +670,31 @@ destroynotify(XEvent *e) { - unmanage(c, True); - } - -+void -+deck(Monitor *m) { -+ unsigned int i, n, h, mw, my; -+ 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; -+ snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n - m->nmaster); -+ } -+ else -+ mw = m->ww; -+ for(i = my = 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), False); -+ my += HEIGHT(c); -+ } -+ else -+ resize(c, m->wx + mw, m->wy, m->ww - mw - (2*c->bw), m->wh - (2*c->bw), False); -+} -+ - void - detach(Client *c) { - Client **tc; --- -2.21.0 - diff --git a/suckless/dwm/patches/dwm-dwmblocks-6.2.diff b/suckless/dwm/patches/dwm-dwmblocks-6.2.diff deleted file mode 100644 index 626175f1..00000000 --- a/suckless/dwm/patches/dwm-dwmblocks-6.2.diff +++ /dev/null @@ -1,340 +0,0 @@ -diff -ruN dwm-6.2-ori/config.def.h dwm-6.2/config.def.h ---- dwm-6.2-ori/config.def.h 2019-02-02 18:25:28.000000000 +0530 -+++ dwm-6.2/config.def.h 2020-07-30 00:13:59.458409207 +0530 -@@ -12,10 +12,34 @@ - static const char col_gray3[] = "#bbbbbb"; - static const char col_gray4[] = "#eeeeee"; - static const char col_cyan[] = "#005577"; -+static const char col1[] = "#ffffff"; -+static const char col2[] = "#ffffff"; -+static const char col3[] = "#ffffff"; -+static const char col4[] = "#ffffff"; -+static const char col5[] = "#ffffff"; -+static const char col6[] = "#ffffff"; -+static const char col7[] = "#ffffff"; -+static const char col8[] = "#ffffff"; -+static const char col9[] = "#ffffff"; -+static const char col10[] = "#ffffff"; -+static const char col11[] = "#ffffff"; -+static const char col12[] = "#ffffff"; - static const char *colors[][3] = { - /* fg bg border */ -- [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, -- [SchemeSel] = { col_gray4, col_cyan, col_cyan }, -+ [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, -+ [SchemeSel] = { col_gray4, col_cyan, col_cyan }, -+ [SchemeCol1] = { col1, col_gray1, col_gray2 }, -+ [SchemeCol2] = { col2, col_gray1, col_gray2 }, -+ [SchemeCol3] = { col3, col_gray1, col_gray2 }, -+ [SchemeCol4] = { col4, col_gray1, col_gray2 }, -+ [SchemeCol5] = { col5, col_gray1, col_gray2 }, -+ [SchemeCol6] = { col6, col_gray1, col_gray2 }, -+ [SchemeCol7] = { col7, col_gray1, col_gray2 }, -+ [SchemeCol8] = { col8, col_gray1, col_gray2 }, -+ [SchemeCol9] = { col8, col_gray1, col_gray2 }, -+ [SchemeCol10] = { col10, col_gray1, col_gray2 }, -+ [SchemeCol11] = { col11, col_gray1, col_gray2 }, -+ [SchemeCol12] = { col12, col_gray1, col_gray2 }, - }; - - /* tagging */ -@@ -103,7 +127,9 @@ - { 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, sigdwmblocks, {.i = 1} }, -+ { ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2} }, -+ { ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3} }, - { ClkClientWin, MODKEY, Button1, movemouse, {0} }, - { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, - { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, -diff -ruN dwm-6.2-ori/dwm.c dwm-6.2/dwm.c ---- dwm-6.2-ori/dwm.c 2019-02-02 18:25:28.000000000 +0530 -+++ dwm-6.2/dwm.c 2020-07-30 00:22:43.991855443 +0530 -@@ -40,6 +40,8 @@ - #include - #endif /* XINERAMA */ - #include -+#include -+#include - - #include "drw.h" - #include "util.h" -@@ -56,10 +58,15 @@ - #define HEIGHT(X) ((X)->h + 2 * (X)->bw) - #define TAGMASK ((1 << LENGTH(tags)) - 1) - #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) -+#define TTEXTW(X) drw_fontset_getwidth(drw, (X)) -+ -+#define DWMBLOCKSLOCKFILE "/tmp/dwmblocks.pid" - - /* enums */ --enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ --enum { SchemeNorm, SchemeSel }; /* color schemes */ -+enum { CurNormal, CurHand, CurResize, CurMove, CurLast }; /* cursor */ -+enum { SchemeNorm, SchemeSel, SchemeCol1, SchemeCol2, SchemeCol3, -+ SchemeCol4, SchemeCol5, SchemeCol6, SchemeCol7, SchemeCol8, -+ SchemeCol9, SchemeCol10, SchemeCol11, SchemeCol12 }; /* color schemes */ - enum { NetSupported, NetWMName, NetWMState, NetWMCheck, - NetWMFullscreen, NetActiveWindow, NetWMWindowType, - NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ -@@ -205,6 +212,7 @@ - static void seturgent(Client *c, int urg); - static void showhide(Client *c); - static void sigchld(int unused); -+static void sigdwmblocks(const Arg *arg); - static void spawn(const Arg *arg); - static void tag(const Arg *arg); - static void tagmon(const Arg *arg); -@@ -216,9 +224,11 @@ - static void unfocus(Client *c, int setfocus); - static void unmanage(Client *c, int destroyed); - static void unmapnotify(XEvent *e); -+static void updatebarcursor(int cursorpos); - static void updatebarpos(Monitor *m); - static void updatebars(void); - static void updateclientlist(void); -+static void updatedwmblockssig(int x, int e); - static int updategeom(void); - static void updatenumlockmask(void); - static void updatesizehints(Client *c); -@@ -236,7 +246,10 @@ - - /* variables */ - static const char broken[] = "broken"; --static char stext[256]; -+static char stextc[256]; -+static char stexts[256]; -+static int wstext; -+static int dwmblockssig; - static int screen; - static int sw, sh; /* X display screen geometry width, height */ - static int bh, blw = 0; /* bar geometry */ -@@ -439,10 +452,14 @@ - arg.ui = 1 << i; - } else if (ev->x < x + blw) - click = ClkLtSymbol; -- else if (ev->x > selmon->ww - TEXTW(stext)) -- click = ClkStatusText; -- else -- click = ClkWinTitle; -+ else if (ev->x < selmon->ww - wstext) -+ click = ClkWinTitle; -+// else if (ev->x < selmon->ww - lrpad / 2 && ev->x >= (x = selmon->ww - wstext + lrpad / 2)) { -+ else if (ev->x < selmon->ww - lrpad / 2 && ev->x >= selmon->ww - wstext + lrpad / 2) { -+ click = ClkStatusText; -+// updatedwmblockssig(x, ev->x); -+ } else -+ return; - } else if ((c = wintoclient(ev->window))) { - focus(c); - restack(selmon); -@@ -695,7 +712,7 @@ - void - drawbar(Monitor *m) - { -- int x, w, sw = 0; -+ int x, w; - int boxs = drw->fonts->h / 9; - int boxw = drw->fonts->h / 6 + 2; - unsigned int i, occ = 0, urg = 0; -@@ -703,9 +720,30 @@ - - /* 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]); -- sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ -- drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0); -+ char *ts = stextc; -+ char *tp = stextc; -+ char ctmp; -+ -+ drw_setscheme(drw, scheme[SchemeNorm]); -+ x = drw_text(drw, m->ww - wstext, 0, lrpad / 2, bh, 0, "", 0); /* to keep left padding clean */ -+ for (;;) { -+ if ((unsigned char)*ts > LENGTH(colors) + 10) { -+ ts++; -+ continue; -+ } -+ ctmp = *ts; -+ *ts = '\0'; -+ if (*tp != '\0') -+ x = drw_text(drw, x, 0, TTEXTW(tp), bh, 0, tp, 0); -+ if (ctmp == '\0') -+ break; -+ /* - 11 to compensate for + 10 above */ -+ drw_setscheme(drw, scheme[(unsigned char)ctmp - 11]); -+ *ts = ctmp; -+ tp = ++ts; -+ } -+ drw_setscheme(drw, scheme[SchemeNorm]); -+ drw_text(drw, x, 0, m->ww - x, bh, 0, "", 0); /* to keep right padding clean */ - } - - for (c = m->clients; c; c = c->next) { -@@ -728,7 +766,7 @@ - drw_setscheme(drw, scheme[SchemeNorm]); - x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); - -- if ((w = m->ww - sw - x) > bh) { -+ if ((w = m->ww - wstext - 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); -@@ -1122,8 +1160,11 @@ - Monitor *m; - XMotionEvent *ev = &e->xmotion; - -- if (ev->window != root) -+ if (ev->window != root) { -+ if (ev->window == selmon->barwin) -+ updatebarcursor(ev->x); - return; -+ } - if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { - unfocus(selmon->sel, 1); - selmon = m; -@@ -1564,6 +1605,7 @@ - netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); - /* init cursors */ - cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); -+ cursor[CurHand] = drw_cur_create(drw, XC_hand2); - cursor[CurResize] = drw_cur_create(drw, XC_sizing); - cursor[CurMove] = drw_cur_create(drw, XC_fleur); - /* init appearance */ -@@ -1637,6 +1679,28 @@ - } - - void -+sigdwmblocks(const Arg *arg) -+{ -+ int fd; -+ struct flock fl; -+ union sigval sv; -+ -+ if (dwmblockssig <= 0 || dwmblockssig >= 10) -+ return; -+ sv.sival_int = (dwmblockssig << 8) | arg->i; -+ fd = open(DWMBLOCKSLOCKFILE, O_RDONLY); -+ if (fd == -1) -+ return; -+ fl.l_type = F_WRLCK; -+ fl.l_start = 0; -+ fl.l_whence = SEEK_SET; -+ fl.l_len = 0; -+ if (fcntl(fd, F_GETLK, &fl) == -1 || fl.l_type == F_UNLCK) -+ return; -+ sigqueue(fl.l_pid, SIGRTMIN, sv); -+} -+ -+void - spawn(const Arg *arg) - { - if (arg->v == dmenucmd) -@@ -1805,7 +1869,7 @@ - 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) { -@@ -1821,6 +1885,33 @@ - } - - void -+updatebarcursor(int cursorpos) -+{ -+ static int currentcursor = 0; -+ int x; -+ -+ if (BETWEEN(cursorpos, (x = selmon->ww - wstext + lrpad / 2), x + wstext - lrpad)) { -+ updatedwmblockssig(x, cursorpos); -+ if (currentcursor) { -+ if (dwmblockssig <= 0 || dwmblockssig >= 10) { -+ currentcursor = 0; -+ XDefineCursor(dpy, selmon->barwin, cursor[CurNormal]->cursor); -+ } -+ } else { -+ if (dwmblockssig > 0 && dwmblockssig < 10) { -+ currentcursor = 1; -+ XDefineCursor(dpy, selmon->barwin, cursor[CurHand]->cursor); -+ } -+ } -+ } else { -+ if (currentcursor) { -+ currentcursor = 0; -+ XDefineCursor(dpy, selmon->barwin, cursor[CurNormal]->cursor); -+ } -+ } -+} -+ -+void - updatebarpos(Monitor *m) - { - m->wy = m->my; -@@ -1847,6 +1938,31 @@ - (unsigned char *) &(c->win), 1); - } - -+void -+updatedwmblockssig(int x, int e) -+{ -+ char *ts = stexts; -+ char *tp = stexts; -+ char ctmp; -+ -+ while (*ts != '\0') { -+ if ((unsigned char)*ts > 10) { -+ ts++; -+ continue; -+ } -+ ctmp = *ts; -+ *ts = '\0'; -+ x += TTEXTW(tp); -+ *ts = ctmp; -+ if (x >= e) { -+ dwmblockssig = (unsigned char)ctmp; -+ return; -+ } -+ tp = ++ts; -+ } -+ dwmblockssig = 0; -+} -+ - int - updategeom(void) - { -@@ -1987,9 +2103,27 @@ - void - updatestatus(void) - { -- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) -- strcpy(stext, "dwm-"VERSION); -- drawbar(selmon); -+ char rawstext[256]; -+ -+ if (gettextprop(root, XA_WM_NAME, rawstext, sizeof rawstext)) { -+ char stextt[256]; -+ char *stc = stextc, *sts = stexts, *stt = stextt; -+ -+ for (char *rt = rawstext; *rt != '\0'; rt++) -+ if ((unsigned char)*rt >= ' ') -+ *(stc++) = *(sts++) = *(stt++) = *rt; -+ else if ((unsigned char)*rt > 10) -+ *(stc++) = *rt; -+ else -+ *(sts++) = *rt; -+ *stc = *sts = *stt = '\0'; -+ wstext = TEXTW(stextt); -+ } else { -+ strcpy(stextc, "dwm-"VERSION); -+ strcpy(stexts, stextc); -+ wstext = TEXTW(stextc); -+ } -+ drawbar(selmon); - } - - void diff --git a/suckless/dwm/patches/dwm-ewmhtags-6.2.diff b/suckless/dwm/patches/dwm-ewmhtags-6.2.diff deleted file mode 100644 index 32abb8c3..00000000 --- a/suckless/dwm/patches/dwm-ewmhtags-6.2.diff +++ /dev/null @@ -1,161 +0,0 @@ -From e5f0eefa921e6bad1e6f75faced0c3ae519995b3 Mon Sep 17 00:00:00 2001 -From: Ryan Kes -Date: Thu, 28 Mar 2019 14:49:28 +0100 -Subject: [PATCH] dwm-ewhmtags-6.2 - ---- - dwm.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 48 insertions(+), 1 deletion(-) - -diff --git a/dwm.c b/dwm.c -index 4465af1..92022a1 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -55,6 +55,7 @@ - #define WIDTH(X) ((X)->w + 2 * (X)->bw) - #define HEIGHT(X) ((X)->h + 2 * (X)->bw) - #define TAGMASK ((1 << LENGTH(tags)) - 1) -+#define TAGSLENGTH (LENGTH(tags)) - #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) - - /* enums */ -@@ -62,7 +63,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, NetDesktopNames, NetDesktopViewport, NetNumberOfDesktops, NetCurrentDesktop, NetLast }; /* EWMH atoms */ - enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ - enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, - ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ -@@ -197,11 +198,15 @@ 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 setcurrentdesktop(void); -+static void setdesktopnames(void); - 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 setnumdesktops(void); - static void setup(void); -+static void setviewport(void); - static void seturgent(Client *c, int urg); - static void showhide(Client *c); - static void sigchld(int unused); -@@ -216,6 +221,7 @@ 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 updatecurrentdesktop(void); - static void updatebarpos(Monitor *m); - static void updatebars(void); - static void updateclientlist(void); -@@ -1431,6 +1437,16 @@ setclientstate(Client *c, long state) - XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, - PropModeReplace, (unsigned char *)data, 2); - } -+void -+setcurrentdesktop(void){ -+ long data[] = { 0 }; -+ XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); -+} -+void setdesktopnames(void){ -+ XTextProperty text; -+ Xutf8TextListToTextProperty(dpy, tags, TAGSLENGTH, XUTF8StringStyle, &text); -+ XSetTextProperty(dpy, root, &text, netatom[NetDesktopNames]); -+} - - int - sendevent(Client *c, Atom proto) -@@ -1457,6 +1473,12 @@ sendevent(Client *c, Atom proto) - return exists; - } - -+void -+setnumdesktops(void){ -+ long data[] = { TAGSLENGTH }; -+ XChangeProperty(dpy, root, netatom[NetNumberOfDesktops], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); -+} -+ - void - setfocus(Client *c) - { -@@ -1562,6 +1584,10 @@ 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[NetDesktopViewport] = XInternAtom(dpy, "_NET_DESKTOP_VIEWPORT", False); -+ netatom[NetNumberOfDesktops] = XInternAtom(dpy, "_NET_NUMBER_OF_DESKTOPS", False); -+ netatom[NetCurrentDesktop] = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False); -+ netatom[NetDesktopNames] = XInternAtom(dpy, "_NET_DESKTOP_NAMES", False); - /* init cursors */ - cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); - cursor[CurResize] = drw_cur_create(drw, XC_sizing); -@@ -1584,6 +1610,10 @@ setup(void) - /* EWMH support per view */ - XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, - PropModeReplace, (unsigned char *) netatom, NetLast); -+ setnumdesktops(); -+ setcurrentdesktop(); -+ setdesktopnames(); -+ setviewport(); - XDeleteProperty(dpy, root, netatom[NetClientList]); - /* select events */ - wa.cursor = cursor[CurNormal]->cursor; -@@ -1595,6 +1625,11 @@ setup(void) - grabkeys(); - focus(NULL); - } -+void -+setviewport(void){ -+ long data[] = { 0, 0 }; -+ XChangeProperty(dpy, root, netatom[NetDesktopViewport], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 2); -+} - - - void -@@ -1732,6 +1767,7 @@ toggletag(const Arg *arg) - focus(NULL); - arrange(selmon); - } -+ updatecurrentdesktop(); - } - - void -@@ -1744,6 +1780,7 @@ toggleview(const Arg *arg) - focus(NULL); - arrange(selmon); - } -+ updatecurrentdesktop(); - } - - void -@@ -1846,6 +1883,15 @@ updateclientlist() - XA_WINDOW, 32, PropModeAppend, - (unsigned char *) &(c->win), 1); - } -+void updatecurrentdesktop(void){ -+ long rawdata[] = { selmon->tagset[selmon->seltags] }; -+ int i=0; -+ while(*rawdata >> i+1){ -+ i++; -+ } -+ long data[] = { i }; -+ XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); -+} - - int - updategeom(void) -@@ -2042,6 +2088,7 @@ view(const Arg *arg) - selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; - focus(NULL); - arrange(selmon); -+ updatecurrentdesktop(); - } - - Client * --- -2.21.0 - diff --git a/suckless/dwm/patches/dwm-fibonacci-5.8.2.diff b/suckless/dwm/patches/dwm-fibonacci-5.8.2.diff deleted file mode 100644 index 78664c89..00000000 --- a/suckless/dwm/patches/dwm-fibonacci-5.8.2.diff +++ /dev/null @@ -1,85 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index cca37df..91b91aa 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -29,1 +29,2 @@ -+#include "fibonacci.c" - static const Layout layouts[] = { -@@ -34,3 +35,5 @@ -+ { "[@]", spiral }, -+ { "[\\]", dwindle }, - }; - - /* key definitions */ -diff --git a/fibonacci.c b/fibonacci.c -new file mode 100644 -index 0000000..fce0a57 ---- /dev/null -+++ b/fibonacci.c -@@ -0,0 +1,66 @@ -+void -+fibonacci(Monitor *mon, int s) { -+ unsigned int i, n, nx, ny, nw, nh; -+ Client *c; -+ -+ for(n = 0, c = nexttiled(mon->clients); c; c = nexttiled(c->next), n++); -+ if(n == 0) -+ return; -+ -+ nx = mon->wx; -+ ny = 0; -+ nw = mon->ww; -+ nh = mon->wh; -+ -+ for(i = 0, c = nexttiled(mon->clients); c; c = nexttiled(c->next)) { -+ if((i % 2 && nh / 2 > 2 * c->bw) -+ || (!(i % 2) && nw / 2 > 2 * c->bw)) { -+ if(i < n - 1) { -+ if(i % 2) -+ nh /= 2; -+ else -+ nw /= 2; -+ if((i % 4) == 2 && !s) -+ nx += nw; -+ else if((i % 4) == 3 && !s) -+ ny += nh; -+ } -+ if((i % 4) == 0) { -+ if(s) -+ ny += nh; -+ else -+ ny -= nh; -+ } -+ else if((i % 4) == 1) -+ nx += nw; -+ else if((i % 4) == 2) -+ ny += nh; -+ else if((i % 4) == 3) { -+ if(s) -+ nx += nw; -+ else -+ nx -= nw; -+ } -+ if(i == 0) -+ { -+ if(n != 1) -+ nw = mon->ww * mon->mfact; -+ ny = mon->wy; -+ } -+ else if(i == 1) -+ nw = mon->ww - nw; -+ i++; -+ } -+ resize(c, nx, ny, nw - 2 * c->bw, nh - 2 * c->bw, False); -+ } -+} -+ -+void -+dwindle(Monitor *mon) { -+ fibonacci(mon, 1); -+} -+ -+void -+spiral(Monitor *mon) { -+ fibonacci(mon, 0); -+} diff --git a/suckless/dwm/patches/dwm-fixborders-6.2.diff b/suckless/dwm/patches/dwm-fixborders-6.2.diff deleted file mode 100644 index 0a17b9e7..00000000 --- a/suckless/dwm/patches/dwm-fixborders-6.2.diff +++ /dev/null @@ -1,27 +0,0 @@ -From 1529909466206016f2101457bbf37c67195714c8 Mon Sep 17 00:00:00 2001 -From: Jakub Leszczak -Date: Fri, 22 Nov 2019 10:46:53 +0800 -Subject: [PATCH] Fix transparent borders - -When terminal has transparency then its borders also become transparent. -Fix it by removing transparency from any pixels drawn. ---- - drw.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/drw.c b/drw.c -index 8fd1ca4..490a592 100644 ---- a/drw.c -+++ b/drw.c -@@ -202,6 +202,8 @@ drw_clr_create(Drw *drw, Clr *dest, const char *clrname) - DefaultColormap(drw->dpy, drw->screen), - clrname, dest)) - die("error, cannot allocate color '%s'", clrname); -+ -+ dest->pixel |= 0xff << 24; - } - - /* Wrapper to create color schemes. The caller has to call free(3) on the --- -2.26.2 - diff --git a/suckless/dwm/patches/dwm-gridmode-20170909-ceac8c9.diff b/suckless/dwm/patches/dwm-gridmode-20170909-ceac8c9.diff deleted file mode 100644 index feec67b0..00000000 --- a/suckless/dwm/patches/dwm-gridmode-20170909-ceac8c9.diff +++ /dev/null @@ -1,73 +0,0 @@ -From b04bb473cf9818277d33a591f7fe2dfae96afaaf Mon Sep 17 00:00:00 2001 -From: Joshua Haase -Date: Mon, 15 Aug 2016 17:06:18 -0500 -Subject: [PATCH] Apply modified gridmode patch. - ---- - config.def.h | 3 +++ - layouts.c | 27 +++++++++++++++++++++++++++ - 2 files changed, 30 insertions(+) - create mode 100644 layouts.c - -diff --git a/config.def.h b/config.def.h -index a9ac303..30b7c4a 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -36,11 +36,13 @@ 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 */ - -+#include "layouts.c" - static const Layout layouts[] = { - /* symbol arrange function */ - { "[]=", tile }, /* first entry is default */ - { "><>", NULL }, /* no layout function means floating behavior */ - { "[M]", monocle }, -+ { "HHH", grid }, - }; - - /* key definitions */ -@@ -76,6 +78,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_g, setlayout, {.v = &layouts[3]} }, - { MODKEY, XK_space, setlayout, {0} }, - { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, - { MODKEY, XK_0, view, {.ui = ~0 } }, -diff --git a/layouts.c b/layouts.c -new file mode 100644 -index 0000000..d26acf3 ---- /dev/null -+++ b/layouts.c -@@ -0,0 +1,27 @@ -+void -+grid(Monitor *m) { -+ unsigned int i, n, cx, cy, cw, ch, aw, ah, cols, rows; -+ Client *c; -+ -+ for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) -+ 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 / (rows ? rows : 1); -+ cw = m->ww / (cols ? cols : 1); -+ for(i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) { -+ cx = m->wx + (i / rows) * cw; -+ cy = m->wy + (i % rows) * ch; -+ /* adjust height/width of last row/column's windows */ -+ ah = ((i + 1) % rows == 0) ? m->wh - ch * rows : 0; -+ aw = (i >= rows * (cols - 1)) ? m->ww - cw * cols : 0; -+ resize(c, cx, cy, cw - 2 * c->bw + aw, ch - 2 * c->bw + ah, False); -+ i++; -+ } -+} --- -2.14.1 - diff --git a/suckless/dwm/patches/dwm-inplacerotate-6.2.diff b/suckless/dwm/patches/dwm-inplacerotate-6.2.diff deleted file mode 100644 index d331368b..00000000 --- a/suckless/dwm/patches/dwm-inplacerotate-6.2.diff +++ /dev/null @@ -1,108 +0,0 @@ -From 75012a6ab9cc1b6c319af7f4ae7d682b16a66ce3 Mon Sep 17 00:00:00 2001 -From: Miles Alan -Date: Sun, 26 Apr 2020 16:05:43 -0500 -Subject: [PATCH] Add inplacerotate fn to rotate all, master, or stacks clients - inplace - -CW (+2) or CCW (-2) Rotates all windows. -CW (+1) or CCW (-1) Rotates master xor stack windows (depending on focus). - -Focus position stays 'in-place' so the area of the screen you are focused -on remains unchanged. ---- - config.def.h | 4 ++++ - dwm.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 63 insertions(+) - -diff --git a/config.def.h b/config.def.h -index 1c0b587..9bcb792 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -66,6 +66,10 @@ static Key keys[] = { - { MODKEY, XK_b, togglebar, {0} }, - { MODKEY, XK_j, focusstack, {.i = +1 } }, - { MODKEY, XK_k, focusstack, {.i = -1 } }, -+ { MODKEY|ShiftMask, XK_j, inplacerotate, {.i = +1} }, -+ { MODKEY|ShiftMask, XK_k, inplacerotate, {.i = -1} }, -+ { MODKEY|ShiftMask, XK_h, inplacerotate, {.i = +2} }, -+ { MODKEY|ShiftMask, XK_l, inplacerotate, {.i = -2} }, - { MODKEY, XK_i, incnmaster, {.i = +1 } }, - { MODKEY, XK_d, incnmaster, {.i = -1 } }, - { MODKEY, XK_h, setmfact, {.f = -0.05} }, -diff --git a/dwm.c b/dwm.c -index 4465af1..3930680 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -175,6 +175,7 @@ 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 inplacerotate(const Arg *arg); - static void keypress(XEvent *e); - static void killclient(const Arg *arg); - static void manage(Window w, XWindowAttributes *wa); -@@ -2147,3 +2148,61 @@ main(int argc, char *argv[]) - XCloseDisplay(dpy); - return EXIT_SUCCESS; - } -+ -+void -+insertclient(Client *item, Client *insertItem, int after) { -+ Client *c; -+ if (item == NULL || insertItem == NULL || item == insertItem) return; -+ detach(insertItem); -+ if (!after && selmon->clients == item) { -+ attach(insertItem); -+ return; -+ } -+ if (after) { -+ c = item; -+ } else { -+ for (c = selmon->clients; c; c = c->next) { if (c->next == item) break; } -+ } -+ insertItem->next = c->next; -+ c->next = insertItem; -+} -+ -+void -+inplacerotate(const Arg *arg) -+{ -+ if(!selmon->sel || (selmon->sel->isfloating && !arg->f)) return; -+ -+ unsigned int selidx = 0, i = 0; -+ Client *c = NULL, *stail = NULL, *mhead = NULL, *mtail = NULL, *shead = NULL; -+ -+ // Determine positionings for insertclient -+ for (c = selmon->clients; c; c = c->next) { -+ if (ISVISIBLE(c) && !(c->isfloating)) { -+ if (selmon->sel == c) { selidx = i; } -+ if (i == selmon->nmaster - 1) { mtail = c; } -+ if (i == selmon->nmaster) { shead = c; } -+ if (mhead == NULL) { mhead = c; } -+ stail = c; -+ i++; -+ } -+ } -+ -+ // All clients rotate -+ if (arg->i == 2) insertclient(selmon->clients, stail, 0); -+ if (arg->i == -2) insertclient(stail, selmon->clients, 1); -+ // Stack xor master rotate -+ if (arg->i == -1 && selidx >= selmon->nmaster) insertclient(stail, shead, 1); -+ if (arg->i == 1 && selidx >= selmon->nmaster) insertclient(shead, stail, 0); -+ if (arg->i == -1 && selidx < selmon->nmaster) insertclient(mtail, mhead, 1); -+ if (arg->i == 1 && selidx < selmon->nmaster) insertclient(mhead, mtail, 0); -+ -+ // Restore focus position -+ i = 0; -+ for (c = selmon->clients; c; c = c->next) { -+ if (!ISVISIBLE(c) || (c->isfloating)) continue; -+ if (i == selidx) { focus(c); break; } -+ i++; -+ } -+ arrange(selmon); -+ focus(c); -+} --- -2.23.1 - diff --git a/suckless/dwm/patches/dwm-leftlayout-20180524-c8e9479.diff b/suckless/dwm/patches/dwm-leftlayout-20180524-c8e9479.diff deleted file mode 100644 index 95466b11..00000000 --- a/suckless/dwm/patches/dwm-leftlayout-20180524-c8e9479.diff +++ /dev/null @@ -1,69 +0,0 @@ -From 73f9b8a4563ff89953459feae5bdbda8bdff94e7 Mon Sep 17 00:00:00 2001 -From: Christopher Drelich -Date: Thu, 24 May 2018 20:40:58 -0400 -Subject: [PATCH] Moved layout symbol to left-hand side. - ---- - dwm.c | 31 +++++++++++++++++-------------- - 1 file changed, 17 insertions(+), 14 deletions(-) - -diff --git a/dwm.c b/dwm.c -index bb95e26..9a57082 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -431,18 +431,21 @@ 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 + blw) -+ x += blw; -+ if (ev->x < x) { - click = ClkLtSymbol; -- else if (ev->x > selmon->ww - TEXTW(stext)) -- click = ClkStatusText; -- else -- click = ClkWinTitle; -+ } else { -+ 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 > selmon->ww - TEXTW(stext)) -+ click = ClkStatusText; -+ else -+ click = ClkWinTitle; -+ } - } else if ((c = wintoclient(ev->window))) { - focus(c); - restack(selmon); -@@ -714,6 +717,9 @@ drawbar(Monitor *m) - urg |= c->tags; - } - x = 0; -+ w = blw = TEXTW(m->ltsymbol); -+ drw_setscheme(drw, scheme[SchemeNorm]); -+ x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); - for (i = 0; i < LENGTH(tags); i++) { - w = TEXTW(tags[i]); - drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); -@@ -724,9 +730,6 @@ drawbar(Monitor *m) - urg & 1 << i); - x += w; - } -- w = blw = 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 - sw - x) > bh) { - if (m->sel) { --- -2.7.4 - diff --git a/suckless/dwm/patches/dwm-movestack-6.1.diff b/suckless/dwm/patches/dwm-movestack-6.1.diff deleted file mode 100644 index a6c83fae..00000000 --- a/suckless/dwm/patches/dwm-movestack-6.1.diff +++ /dev/null @@ -1,73 +0,0 @@ -diff -r 050d521d66d8 config.def.h ---- a/config.def.h Tue Aug 24 13:13:20 2010 +0100 -+++ b/config.def.h Sun Sep 05 18:43:07 2010 +0200 -@@ -57,6 +57,7 @@ - static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL }; - static const char *termcmd[] = { "st", NULL }; - -+#include "movestack.c" - static Key keys[] = { - /* modifier key function argument */ - { MODKEY, XK_p, spawn, {.v = dmenucmd } }, -@@ -68,6 +69,8 @@ - { MODKEY, XK_d, incnmaster, {.i = -1 } }, - { MODKEY, XK_h, setmfact, {.f = -0.05} }, - { MODKEY, XK_l, setmfact, {.f = +0.05} }, -+ { MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } }, -+ { MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } }, - { MODKEY, XK_Return, zoom, {0} }, - { MODKEY, XK_Tab, view, {0} }, - { MODKEY|ShiftMask, XK_c, killclient, {0} }, -diff -r 050d521d66d8 movestack.c ---- /dev/null Thu Jan 01 00:00:00 1970 +0000 -+++ b/movestack.c Sun Sep 05 18:43:07 2010 +0200 -@@ -0,0 +1,49 @@ -+void -+movestack(const Arg *arg) { -+ Client *c = NULL, *p = NULL, *pc = NULL, *i; -+ -+ if(arg->i > 0) { -+ /* find the client after selmon->sel */ -+ for(c = selmon->sel->next; c && (!ISVISIBLE(c) || c->isfloating); c = c->next); -+ if(!c) -+ for(c = selmon->clients; c && (!ISVISIBLE(c) || c->isfloating); c = c->next); -+ -+ } -+ else { -+ /* find the client before selmon->sel */ -+ for(i = selmon->clients; i != selmon->sel; i = i->next) -+ if(ISVISIBLE(i) && !i->isfloating) -+ c = i; -+ if(!c) -+ for(; i; i = i->next) -+ if(ISVISIBLE(i) && !i->isfloating) -+ c = i; -+ } -+ /* find the client before selmon->sel and c */ -+ for(i = selmon->clients; i && (!p || !pc); i = i->next) { -+ if(i->next == selmon->sel) -+ p = i; -+ if(i->next == c) -+ pc = i; -+ } -+ -+ /* swap c and selmon->sel selmon->clients in the selmon->clients list */ -+ if(c && c != selmon->sel) { -+ Client *temp = selmon->sel->next==c?selmon->sel:selmon->sel->next; -+ selmon->sel->next = c->next==selmon->sel?c:c->next; -+ c->next = temp; -+ -+ if(p && p != c) -+ p->next = c; -+ if(pc && pc != selmon->sel) -+ pc->next = selmon->sel; -+ -+ if(selmon->sel == selmon->clients) -+ selmon->clients = c; -+ else if(c == selmon->clients) -+ selmon->clients = selmon->sel; -+ -+ arrange(selmon); -+ } -+} -+ diff --git a/suckless/dwm/patches/dwm-netclientliststacking-6.2.diff b/suckless/dwm/patches/dwm-netclientliststacking-6.2.diff deleted file mode 100644 index 18d857f5..00000000 --- a/suckless/dwm/patches/dwm-netclientliststacking-6.2.diff +++ /dev/null @@ -1,65 +0,0 @@ -From 67840904a9510d6a6fc991b7f04046e74d196a26 Mon Sep 17 00:00:00 2001 -From: bakkeby -Date: Sun, 25 Oct 2020 16:40:05 +0100 -Subject: [PATCH] Adds the _NET_CLIENT_LIST_STACKING property which may be - needed by some applications, e.g. zoom for window sharing. - ---- - dwm.c | 13 ++++++++++++- - 1 file changed, 12 insertions(+), 1 deletion(-) - -diff --git a/dwm.c b/dwm.c -index 4465af1..0be261f 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, NetClientListStacking, NetLast }; /* EWMH atoms */ - enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ - enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, - ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ -@@ -1066,6 +1066,8 @@ manage(Window w, XWindowAttributes *wa) - attachstack(c); - XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, - (unsigned char *) &(c->win), 1); -+ XChangeProperty(dpy, root, netatom[NetClientListStacking], XA_WINDOW, 32, PropModePrepend, -+ (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 (c->mon == selmon) -@@ -1562,6 +1564,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[NetClientListStacking] = XInternAtom(dpy, "_NET_CLIENT_LIST_STACKING", False); - /* init cursors */ - cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); - cursor[CurResize] = drw_cur_create(drw, XC_sizing); -@@ -1585,6 +1588,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[NetClientListStacking]); - /* select events */ - wa.cursor = cursor[CurNormal]->cursor; - wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask -@@ -1845,6 +1849,13 @@ updateclientlist() - XChangeProperty(dpy, root, netatom[NetClientList], - XA_WINDOW, 32, PropModeAppend, - (unsigned char *) &(c->win), 1); -+ -+ XDeleteProperty(dpy, root, netatom[NetClientListStacking]); -+ for (m = mons; m; m = m->next) -+ for (c = m->stack; c; c = c->snext) -+ XChangeProperty(dpy, root, netatom[NetClientListStacking], -+ XA_WINDOW, 32, PropModeAppend, -+ (unsigned char *) &(c->win), 1); - } - - int --- -2.19.1 - diff --git a/suckless/dwm/patches/dwm-pertag-20170513-ceac8c9.diff b/suckless/dwm/patches/dwm-pertag-20170513-ceac8c9.diff deleted file mode 100644 index 1a2a3cf3..00000000 --- a/suckless/dwm/patches/dwm-pertag-20170513-ceac8c9.diff +++ /dev/null @@ -1,177 +0,0 @@ -diff --git a/dwm.c b/dwm.c -index a5ce993..45f1e27 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -112,6 +112,7 @@ typedef struct { - void (*arrange)(Monitor *); - } Layout; - -+typedef struct Pertag Pertag; - struct Monitor { - char ltsymbol[16]; - float mfact; -@@ -131,6 +132,7 @@ struct Monitor { - Monitor *next; - Window barwin; - const Layout *lt[2]; -+ Pertag *pertag; - }; - - typedef struct { -@@ -272,6 +274,15 @@ 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 */ -+}; -+ - /* compile-time check if all tags fit into an unsigned int bit array. */ - struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; - -@@ -632,6 +643,7 @@ Monitor * - createmon(void) - { - Monitor *m; -+ unsigned int i; - - m = ecalloc(1, sizeof(Monitor)); - m->tagset[0] = m->tagset[1] = 1; -@@ -642,6 +654,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; - } - -@@ -968,7 +994,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); - } - -@@ -1503,9 +1529,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); -@@ -1524,7 +1550,7 @@ setmfact(const Arg *arg) - f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; - if (f < 0.1 || f > 0.9) - return; -- selmon->mfact = f; -+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; - arrange(selmon); - } - -@@ -1701,7 +1727,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); -@@ -1740,9 +1766,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); - } -@@ -2036,11 +2086,37 @@ 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; -+ 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(NULL); - arrange(selmon); - } diff --git a/suckless/dwm/patches/dwm-rmaster-6.1.diff b/suckless/dwm/patches/dwm-rmaster-6.1.diff deleted file mode 100644 index f8a14496..00000000 --- a/suckless/dwm/patches/dwm-rmaster-6.1.diff +++ /dev/null @@ -1,113 +0,0 @@ -From 3aca05f642469799086acbc243e173cfda527683 Mon Sep 17 00:00:00 2001 -From: aleks -Date: Thu, 23 May 2019 22:39:13 +0200 -Subject: [PATCH] Enable swapping master- and stack-area - -Enables swapping the master- and stack area such that the master-client -appears on the right and the stack-clients appear on the left. - -A variable and a toggle-function are introduced to achieve this -behaviour which are set in the config.h: - -* The rmaster-variable can be set to 1 to make the right area the -default master-area -* The togglemaster-function can be used to swap the master- and -stack-areas dynamically. ---- - config.def.h | 2 ++ - dwm.c | 23 ++++++++++++++++++++--- - 2 files changed, 22 insertions(+), 3 deletions(-) - -diff --git a/config.def.h b/config.def.h -index 7054c06..5a69035 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -13,6 +13,7 @@ static const char selbgcolor[] = "#005577"; - static const char selfgcolor[] = "#eeeeee"; - static const unsigned int borderpx = 1; /* border pixel of windows */ - static const unsigned int snap = 32; /* snap pixel */ -+static const int rmaster = 1; /* 1 means master-area is initially on the right */ - static const int showbar = 1; /* 0 means no bar */ - static const int topbar = 1; /* 0 means bottom bar */ - -@@ -76,6 +77,7 @@ static Key keys[] = { - { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, - { MODKEY, XK_space, setlayout, {0} }, - { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, -+ { MODKEY, XK_r, togglermaster, {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 0362114..e11bd8b 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -122,6 +122,7 @@ struct Monitor { - unsigned int seltags; - unsigned int sellt; - unsigned int tagset[2]; -+ int rmaster; - int showbar; - int topbar; - Client *clients; -@@ -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 togglermaster(const Arg *arg); - static void toggletag(const Arg *arg); - static void toggleview(const Arg *arg); - static void unfocus(Client *c, int setfocus); -@@ -645,6 +647,7 @@ createmon(void) - m->tagset[0] = m->tagset[1] = 1; - m->mfact = mfact; - m->nmaster = nmaster; -+ m->rmaster = rmaster; - m->showbar = showbar; - m->topbar = topbar; - m->lt[0] = &layouts[0]; -@@ -1674,17 +1677,21 @@ tile(Monitor *m) - return; - - if (n > m->nmaster) -- mw = m->nmaster ? m->ww * m->mfact : 0; -+ mw = m->nmaster -+ ? m->ww * (m->rmaster ? 1.0 - m->mfact : 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); -+ resize(c, m->rmaster ? m->wx + m->ww - mw : m->wx, -+ m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); - 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); -+ resize(c, m->rmaster ? m->wx : m->wx + mw, m->wy + ty, -+ m->ww - mw - (2*c->bw), h - (2*c->bw), 0); - ty += HEIGHT(c); - } - } -@@ -1712,6 +1719,16 @@ togglefloating(const Arg *arg) - arrange(selmon); - } - -+void -+togglermaster(const Arg *arg) -+{ -+ selmon->rmaster = !selmon->rmaster; -+ /* now mfact represents the left factor */ -+ selmon->mfact = 1.0 - selmon->mfact; -+ if (selmon->lt[selmon->sellt]->arrange) -+ arrange(selmon); -+} -+ - void - toggletag(const Arg *arg) - { --- -2.21.0 - diff --git a/suckless/dwm/patches/dwm-statuspadding-20150524-c8e9479.diff b/suckless/dwm/patches/dwm-statuspadding-20150524-c8e9479.diff deleted file mode 100644 index eab4bf90..00000000 --- a/suckless/dwm/patches/dwm-statuspadding-20150524-c8e9479.diff +++ /dev/null @@ -1,62 +0,0 @@ -From 75d5edbe16ee2fc060ff8b05eea17791d6334a59 Mon Sep 17 00:00:00 2001 -From: Christopher Drelich -Date: Thu, 24 May 2018 23:24:12 -0400 -Subject: [PATCH] Replaces magic numbers in statusbar with configurable - variables. - -horizpadbar for horizontal statusbar padding -vertpadbar for vertical statusbar padding - -StatusText now has both left and right padding, -as well as the vertical padding that all of the statusbar shares. - -Other than the addition of left padding to StatusText, appearance -of the statusbar is identical to pre-patch when using the defaults -in config.def.h ---- - config.def.h | 2 ++ - dwm.c | 8 ++++---- - 2 files changed, 6 insertions(+), 4 deletions(-) - -diff --git a/config.def.h b/config.def.h -index a9ac303..5819399 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 horizpadbar = 2; /* horizontal padding for statusbar */ -+static const int vertpadbar = 0; /* vertical padding for statusbar */ - 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 bb95e26..7b9ed42 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -704,8 +704,8 @@ 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]); -- sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ -- drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0); -+ sw = TEXTW(stext); -+ drw_text(drw, m->ww - sw, 0, sw, bh, lrpad / 2, stext, 0); - } - - for (c = m->clients; c; c = c->next) { -@@ -1544,8 +1544,8 @@ setup(void) - drw = drw_create(dpy, screen, root, sw, sh); - if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) - die("no fonts could be loaded."); -- lrpad = drw->fonts->h; -- bh = drw->fonts->h + 2; -+ lrpad = drw->fonts->h + horizpadbar; -+ bh = drw->fonts->h + vertpadbar; - updategeom(); - /* init atoms */ - utf8string = XInternAtom(dpy, "UTF8_STRING", False); --- -2.7.4 - diff --git a/suckless/dwm/patches/dwm-switchcol-6.1.diff b/suckless/dwm/patches/dwm-switchcol-6.1.diff deleted file mode 100644 index 14c0c78c..00000000 --- a/suckless/dwm/patches/dwm-switchcol-6.1.diff +++ /dev/null @@ -1,47 +0,0 @@ -diff -urp dwm-6.1/dwm.c dwm-6.1-patched/dwm.c ---- dwm-6.1/dwm.c 2015-11-09 06:39:37.000000000 +0800 -+++ dwm-6.1-patched/dwm.c 2016-03-24 23:56:35.435047948 +0800 -@@ -206,6 +206,7 @@ static void setup(void); - static void showhide(Client *c); - static void sigchld(int unused); - static void spawn(const Arg *arg); -+static void switchcol(const Arg *arg); - static void tag(const Arg *arg); - static void tagmon(const Arg *arg); - static void tile(Monitor *); -@@ -1645,6 +1646,35 @@ spawn(const Arg *arg) - } - } - -+void -+switchcol(const Arg *arg) -+{ -+ Client *c, *t; -+ int col = 0; -+ int i; -+ -+ if (!selmon->sel) -+ return; -+ for (i = 0, c = nexttiled(selmon->clients); c ; -+ c = nexttiled(c->next), i++) { -+ if (c == selmon->sel) -+ col = (i + 1) > selmon->nmaster; -+ } -+ if (i <= selmon->nmaster) -+ return; -+ for (c = selmon->stack; c; c = c->snext) { -+ if (!ISVISIBLE(c)) -+ continue; -+ for (i = 0, t = nexttiled(selmon->clients); t && t != c; -+ t = nexttiled(t->next), i++); -+ if (t && (i + 1 > selmon->nmaster) != col) { -+ focus(c); -+ restack(selmon); -+ break; -+ } -+ } -+} -+ - void - tag(const Arg *arg) - { diff --git a/suckless/dwm/patches/dwm-systray-20200914-61bb8b2.diff b/suckless/dwm/patches/dwm-systray-20200914-61bb8b2.diff deleted file mode 100644 index b2a4d572..00000000 --- a/suckless/dwm/patches/dwm-systray-20200914-61bb8b2.diff +++ /dev/null @@ -1,727 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index 1c0b587..2d824d1 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -3,6 +3,10 @@ - /* appearance */ - static const unsigned int borderpx = 1; /* border pixel of windows */ - static const unsigned int snap = 32; /* snap pixel */ -+static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ -+static const unsigned int systrayspacing = 2; /* systray spacing */ -+static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ -+static const int showsystray = 1; /* 0 means no systray */ - 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" }; -diff --git a/dwm.c b/dwm.c -index 664c527..abce13d 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -57,12 +57,30 @@ - #define TAGMASK ((1 << LENGTH(tags)) - 1) - #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) - -+#define SYSTEM_TRAY_REQUEST_DOCK 0 -+ -+/* XEMBED messages */ -+#define XEMBED_EMBEDDED_NOTIFY 0 -+#define XEMBED_WINDOW_ACTIVATE 1 -+#define XEMBED_FOCUS_IN 4 -+#define XEMBED_MODALITY_ON 10 -+ -+#define XEMBED_MAPPED (1 << 0) -+#define XEMBED_WINDOW_ACTIVATE 1 -+#define XEMBED_WINDOW_DEACTIVATE 2 -+ -+#define VERSION_MAJOR 0 -+#define VERSION_MINOR 0 -+#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR -+ - /* enums */ - enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ - enum { SchemeNorm, SchemeSel }; /* color schemes */ - enum { NetSupported, NetWMName, NetWMState, NetWMCheck, -+ NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz, - NetWMFullscreen, NetActiveWindow, NetWMWindowType, - NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ -+enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ - enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ - enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, - ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ -@@ -141,6 +159,12 @@ typedef struct { - int monitor; - } Rule; - -+typedef struct Systray Systray; -+struct Systray { -+ Window win; -+ Client *icons; -+}; -+ - /* function declarations */ - static void applyrules(Client *c); - static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); -@@ -172,6 +196,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 unsigned int getsystraywidth(); - static int gettextprop(Window w, Atom atom, char *text, unsigned int size); - static void grabbuttons(Client *c, int focused); - static void grabkeys(void); -@@ -189,13 +214,16 @@ 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 removesystrayicon(Client *i); - static void resize(Client *c, int x, int y, int w, int h, int interact); -+static void resizebarwin(Monitor *m); - static void resizeclient(Client *c, int x, int y, int w, int h); - static void resizemouse(const Arg *arg); -+static void resizerequest(XEvent *e); - static void restack(Monitor *m); - static void run(void); - static void scan(void); --static int sendevent(Client *c, Atom proto); -+static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); - static void sendmon(Client *c, Monitor *m); - static void setclientstate(Client *c, long state); - static void setfocus(Client *c); -@@ -207,6 +235,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 Monitor *systraytomon(Monitor *m); - static void tag(const Arg *arg); - static void tagmon(const Arg *arg); - static void tile(Monitor *); -@@ -224,18 +253,23 @@ static int updategeom(void); - static void updatenumlockmask(void); - static void updatesizehints(Client *c); - static void updatestatus(void); -+static void updatesystray(void); -+static void updatesystrayicongeom(Client *i, int w, int h); -+static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); - static void updatetitle(Client *c); - static void updatewindowtype(Client *c); - static void updatewmhints(Client *c); - static void view(const Arg *arg); - static Client *wintoclient(Window w); - static Monitor *wintomon(Window w); -+static Client *wintosystrayicon(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 Systray *systray = NULL; - static const char broken[] = "broken"; - static char stext[256]; - static int screen; -@@ -258,9 +292,10 @@ static void (*handler[LASTEvent]) (XEvent *) = { - [MapRequest] = maprequest, - [MotionNotify] = motionnotify, - [PropertyNotify] = propertynotify, -+ [ResizeRequest] = resizerequest, - [UnmapNotify] = unmapnotify - }; --static Atom wmatom[WMLast], netatom[NetLast]; -+static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; - static int running = 1; - static Cur *cursor[CurLast]; - static Clr **scheme; -@@ -440,7 +475,7 @@ buttonpress(XEvent *e) - arg.ui = 1 << i; - } else if (ev->x < x + blw) - click = ClkLtSymbol; -- else if (ev->x > selmon->ww - (int)TEXTW(stext)) -+ else if (ev->x > selmon->ww - (int)TEXTW(stext) - getsystraywidth()) - click = ClkStatusText; - else - click = ClkWinTitle; -@@ -483,6 +518,11 @@ cleanup(void) - XUngrabKey(dpy, AnyKey, AnyModifier, root); - while (mons) - cleanupmon(mons); -+ if (showsystray) { -+ XUnmapWindow(dpy, systray->win); -+ XDestroyWindow(dpy, systray->win); -+ free(systray); -+ } - for (i = 0; i < CurLast; i++) - drw_cur_free(drw, cursor[i]); - for (i = 0; i < LENGTH(colors); i++) -@@ -513,9 +553,57 @@ cleanupmon(Monitor *mon) - void - clientmessage(XEvent *e) - { -+ XWindowAttributes wa; -+ XSetWindowAttributes swa; - XClientMessageEvent *cme = &e->xclient; - Client *c = wintoclient(cme->window); - -+ if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { -+ /* add systray icons */ -+ if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { -+ if (!(c = (Client *)calloc(1, sizeof(Client)))) -+ die("fatal: could not malloc() %u bytes\n", sizeof(Client)); -+ if (!(c->win = cme->data.l[2])) { -+ free(c); -+ return; -+ } -+ c->mon = selmon; -+ c->next = systray->icons; -+ systray->icons = c; -+ if (!XGetWindowAttributes(dpy, c->win, &wa)) { -+ /* use sane defaults */ -+ wa.width = bh; -+ wa.height = bh; -+ wa.border_width = 0; -+ } -+ c->x = c->oldx = c->y = c->oldy = 0; -+ c->w = c->oldw = wa.width; -+ c->h = c->oldh = wa.height; -+ c->oldbw = wa.border_width; -+ c->bw = 0; -+ c->isfloating = True; -+ /* reuse tags field as mapped status */ -+ c->tags = 1; -+ updatesizehints(c); -+ updatesystrayicongeom(c, wa.width, wa.height); -+ XAddToSaveSet(dpy, c->win); -+ XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); -+ XReparentWindow(dpy, c->win, systray->win, 0, 0); -+ /* use parents background color */ -+ swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; -+ XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); -+ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION); -+ /* FIXME not sure if I have to send these events, too */ -+ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION); -+ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION); -+ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION); -+ XSync(dpy, False); -+ resizebarwin(selmon); -+ updatesystray(); -+ setclientstate(c, NormalState); -+ } -+ return; -+ } - if (!c) - return; - if (cme->message_type == netatom[NetWMState]) { -@@ -568,7 +656,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); -+ resizebarwin(m); - } - focus(NULL); - arrange(NULL); -@@ -653,6 +741,11 @@ destroynotify(XEvent *e) - - if ((c = wintoclient(ev->window))) - unmanage(c, 1); -+ else if ((c = wintosystrayicon(ev->window))) { -+ removesystrayicon(c); -+ resizebarwin(selmon); -+ updatesystray(); -+ } - } - - void -@@ -696,19 +789,23 @@ dirtomon(int dir) - void - drawbar(Monitor *m) - { -- int x, w, tw = 0; -+ int x, w, tw = 0, stw = 0; - int boxs = drw->fonts->h / 9; - int boxw = drw->fonts->h / 6 + 2; - unsigned int i, occ = 0, urg = 0; - Client *c; - -+ if(showsystray && m == systraytomon(m)) -+ stw = getsystraywidth(); -+ - /* 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]); -- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ -- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); -+ tw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ -+ drw_text(drw, m->ww - tw - stw, 0, tw, bh, lrpad / 2 - 2, stext, 0); - } - -+ resizebarwin(m); - for (c = m->clients; c; c = c->next) { - occ |= c->tags; - if (c->isurgent) -@@ -729,7 +826,7 @@ drawbar(Monitor *m) - 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 ((w = m->ww - tw - stw - 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); -@@ -740,7 +837,7 @@ drawbar(Monitor *m) - drw_rect(drw, x, 0, w, bh, 1, 1); - } - } -- drw_map(drw, m->barwin, 0, 0, m->ww, bh); -+ drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh); - } - - void -@@ -777,8 +874,11 @@ expose(XEvent *e) - Monitor *m; - XExposeEvent *ev = &e->xexpose; - -- if (ev->count == 0 && (m = wintomon(ev->window))) -+ if (ev->count == 0 && (m = wintomon(ev->window))) { - drawbar(m); -+ if (m == selmon) -+ updatesystray(); -+ } - } - - void -@@ -863,10 +963,17 @@ getatomprop(Client *c, Atom prop) - unsigned long dl; - unsigned char *p = NULL; - Atom da, atom = None; -+ /* FIXME getatomprop should return the number of items and a pointer to -+ * the stored data instead of this workaround */ -+ Atom req = XA_ATOM; -+ if (prop == xatom[XembedInfo]) -+ req = xatom[XembedInfo]; - -- if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, -+ if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, - &da, &di, &dl, &dl, &p) == Success && p) { - atom = *(Atom *)p; -+ if (da == xatom[XembedInfo] && dl == 2) -+ atom = ((Atom *)p)[1]; - XFree(p); - } - return atom; -@@ -900,6 +1007,16 @@ getstate(Window w) - return result; - } - -+unsigned int -+getsystraywidth() -+{ -+ unsigned int w = 0; -+ Client *i; -+ if(showsystray) -+ for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ; -+ return w ? w + systrayspacing : 1; -+} -+ - int - gettextprop(Window w, Atom atom, char *text, unsigned int size) - { -@@ -1004,7 +1121,7 @@ killclient(const Arg *arg) - { - if (!selmon->sel) - return; -- if (!sendevent(selmon->sel, wmatom[WMDelete])) { -+ if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { - XGrabServer(dpy); - XSetErrorHandler(xerrordummy); - XSetCloseDownMode(dpy, DestroyAll); -@@ -1092,6 +1209,12 @@ maprequest(XEvent *e) - { - static XWindowAttributes wa; - XMapRequestEvent *ev = &e->xmaprequest; -+ Client *i; -+ if ((i = wintosystrayicon(ev->window))) { -+ sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); -+ resizebarwin(selmon); -+ updatesystray(); -+ } - - if (!XGetWindowAttributes(dpy, ev->window, &wa)) - return; -@@ -1216,6 +1339,16 @@ propertynotify(XEvent *e) - Window trans; - XPropertyEvent *ev = &e->xproperty; - -+ if ((c = wintosystrayicon(ev->window))) { -+ if (ev->atom == XA_WM_NORMAL_HINTS) { -+ updatesizehints(c); -+ updatesystrayicongeom(c, c->w, c->h); -+ } -+ else -+ updatesystrayiconstate(c, ev); -+ resizebarwin(selmon); -+ updatesystray(); -+ } - if ((ev->window == root) && (ev->atom == XA_WM_NAME)) - updatestatus(); - else if (ev->state == PropertyDelete) -@@ -1266,6 +1399,20 @@ recttomon(int x, int y, int w, int h) - return r; - } - -+void -+removesystrayicon(Client *i) -+{ -+ Client **ii; -+ -+ if (!showsystray || !i) -+ return; -+ for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); -+ if (ii) -+ *ii = i->next; -+ free(i); -+} -+ -+ - void - resize(Client *c, int x, int y, int w, int h, int interact) - { -@@ -1273,6 +1420,14 @@ resize(Client *c, int x, int y, int w, int h, int interact) - resizeclient(c, x, y, w, h); - } - -+void -+resizebarwin(Monitor *m) { -+ unsigned int w = m->ww; -+ if (showsystray && m == systraytomon(m)) -+ w -= getsystraywidth(); -+ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); -+} -+ - void - resizeclient(Client *c, int x, int y, int w, int h) - { -@@ -1345,6 +1500,19 @@ resizemouse(const Arg *arg) - } - } - -+void -+resizerequest(XEvent *e) -+{ -+ XResizeRequestEvent *ev = &e->xresizerequest; -+ Client *i; -+ -+ if ((i = wintosystrayicon(ev->window))) { -+ updatesystrayicongeom(i, ev->width, ev->height); -+ resizebarwin(selmon); -+ updatesystray(); -+ } -+} -+ - void - restack(Monitor *m) - { -@@ -1434,26 +1602,36 @@ setclientstate(Client *c, long state) - } - - int --sendevent(Client *c, Atom proto) -+sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) - { - int n; -- Atom *protocols; -+ Atom *protocols, mt; - int exists = 0; - XEvent ev; - -- if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { -- while (!exists && n--) -- exists = protocols[n] == proto; -- XFree(protocols); -+ if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { -+ mt = wmatom[WMProtocols]; -+ if (XGetWMProtocols(dpy, w, &protocols, &n)) { -+ while (!exists && n--) -+ exists = protocols[n] == proto; -+ XFree(protocols); -+ } -+ } -+ else { -+ exists = True; -+ mt = proto; - } - if (exists) { - ev.type = ClientMessage; -- ev.xclient.window = c->win; -- ev.xclient.message_type = wmatom[WMProtocols]; -+ ev.xclient.window = w; -+ ev.xclient.message_type = mt; - ev.xclient.format = 32; -- ev.xclient.data.l[0] = proto; -- ev.xclient.data.l[1] = CurrentTime; -- XSendEvent(dpy, c->win, False, NoEventMask, &ev); -+ ev.xclient.data.l[0] = d0; -+ ev.xclient.data.l[1] = d1; -+ ev.xclient.data.l[2] = d2; -+ ev.xclient.data.l[3] = d3; -+ ev.xclient.data.l[4] = d4; -+ XSendEvent(dpy, w, False, mask, &ev); - } - return exists; - } -@@ -1467,7 +1645,7 @@ setfocus(Client *c) - XA_WINDOW, 32, PropModeReplace, - (unsigned char *) &(c->win), 1); - } -- sendevent(c, wmatom[WMTakeFocus]); -+ sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); - } - - void -@@ -1556,6 +1734,10 @@ setup(void) - wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); - netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); - netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); -+ netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False); -+ netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); -+ netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); -+ netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", 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); -@@ -1563,6 +1745,9 @@ 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); -+ xatom[Manager] = XInternAtom(dpy, "MANAGER", False); -+ xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); -+ xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); - /* init cursors */ - cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); - cursor[CurResize] = drw_cur_create(drw, XC_sizing); -@@ -1571,6 +1756,8 @@ setup(void) - scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); - for (i = 0; i < LENGTH(colors); i++) - scheme[i] = drw_scm_create(drw, colors[i], 3); -+ /* init system tray */ -+ updatesystray(); - /* init bars */ - updatebars(); - updatestatus(); -@@ -1704,7 +1891,18 @@ togglebar(const Arg *arg) - { - selmon->showbar = !selmon->showbar; - updatebarpos(selmon); -- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); -+ resizebarwin(selmon); -+ if (showsystray) { -+ XWindowChanges wc; -+ if (!selmon->showbar) -+ wc.y = -bh; -+ else if (selmon->showbar) { -+ wc.y = 0; -+ if (!selmon->topbar) -+ wc.y = selmon->mh - bh; -+ } -+ XConfigureWindow(dpy, systray->win, CWY, &wc); -+ } - arrange(selmon); - } - -@@ -1799,11 +1997,18 @@ unmapnotify(XEvent *e) - else - unmanage(c, 0); - } -+ else if ((c = wintosystrayicon(ev->window))) { -+ /* KLUDGE! sometimes icons occasionally unmap their windows, but do -+ * _not_ destroy them. We map those windows back */ -+ XMapRaised(dpy, c->win); -+ updatesystray(); -+ } - } - - void - updatebars(void) - { -+ unsigned int w; - Monitor *m; - XSetWindowAttributes wa = { - .override_redirect = True, -@@ -1814,10 +2019,15 @@ 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), -+ w = m->ww; -+ if (showsystray && m == systraytomon(m)) -+ w -= getsystraywidth(); -+ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen), - CopyFromParent, DefaultVisual(dpy, screen), - CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); - XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); -+ if (showsystray && m == systraytomon(m)) -+ XMapRaised(dpy, systray->win); - XMapRaised(dpy, m->barwin); - XSetClassHint(dpy, m->barwin, &ch); - } -@@ -1993,6 +2203,121 @@ updatestatus(void) - if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) - strcpy(stext, "dwm-"VERSION); - drawbar(selmon); -+ updatesystray(); -+} -+ -+void -+updatesystrayicongeom(Client *i, int w, int h) -+{ -+ if (i) { -+ i->h = bh; -+ if (w == h) -+ i->w = bh; -+ else if (h == bh) -+ i->w = w; -+ else -+ i->w = (int) ((float)bh * ((float)w / (float)h)); -+ applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); -+ /* force icons into the systray dimensions if they don't want to */ -+ if (i->h > bh) { -+ if (i->w == i->h) -+ i->w = bh; -+ else -+ i->w = (int) ((float)bh * ((float)i->w / (float)i->h)); -+ i->h = bh; -+ } -+ } -+} -+ -+void -+updatesystrayiconstate(Client *i, XPropertyEvent *ev) -+{ -+ long flags; -+ int code = 0; -+ -+ if (!showsystray || !i || ev->atom != xatom[XembedInfo] || -+ !(flags = getatomprop(i, xatom[XembedInfo]))) -+ return; -+ -+ if (flags & XEMBED_MAPPED && !i->tags) { -+ i->tags = 1; -+ code = XEMBED_WINDOW_ACTIVATE; -+ XMapRaised(dpy, i->win); -+ setclientstate(i, NormalState); -+ } -+ else if (!(flags & XEMBED_MAPPED) && i->tags) { -+ i->tags = 0; -+ code = XEMBED_WINDOW_DEACTIVATE; -+ XUnmapWindow(dpy, i->win); -+ setclientstate(i, WithdrawnState); -+ } -+ else -+ return; -+ sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0, -+ systray->win, XEMBED_EMBEDDED_VERSION); -+} -+ -+void -+updatesystray(void) -+{ -+ XSetWindowAttributes wa; -+ XWindowChanges wc; -+ Client *i; -+ Monitor *m = systraytomon(NULL); -+ unsigned int x = m->mx + m->mw; -+ unsigned int w = 1; -+ -+ if (!showsystray) -+ return; -+ if (!systray) { -+ /* init systray */ -+ if (!(systray = (Systray *)calloc(1, sizeof(Systray)))) -+ die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); -+ systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel); -+ wa.event_mask = ButtonPressMask | ExposureMask; -+ wa.override_redirect = True; -+ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; -+ XSelectInput(dpy, systray->win, SubstructureNotifyMask); -+ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, -+ PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1); -+ XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa); -+ XMapRaised(dpy, systray->win); -+ XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); -+ if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { -+ sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0); -+ XSync(dpy, False); -+ } -+ else { -+ fprintf(stderr, "dwm: unable to obtain system tray.\n"); -+ free(systray); -+ systray = NULL; -+ return; -+ } -+ } -+ for (w = 0, i = systray->icons; i; i = i->next) { -+ /* make sure the background color stays the same */ -+ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; -+ XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); -+ XMapRaised(dpy, i->win); -+ w += systrayspacing; -+ i->x = w; -+ XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); -+ w += i->w; -+ if (i->mon != m) -+ i->mon = m; -+ } -+ w = w ? w + systrayspacing : 1; -+ x -= w; -+ XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh); -+ wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh; -+ wc.stack_mode = Above; wc.sibling = m->barwin; -+ XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc); -+ XMapWindow(dpy, systray->win); -+ XMapSubwindows(dpy, systray->win); -+ /* redraw background */ -+ XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel); -+ XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); -+ XSync(dpy, False); - } - - void -@@ -2060,6 +2385,16 @@ wintoclient(Window w) - return NULL; - } - -+Client * -+wintosystrayicon(Window w) { -+ Client *i = NULL; -+ -+ if (!showsystray || !w) -+ return i; -+ for (i = systray->icons; i && i->win != w; i = i->next) ; -+ return i; -+} -+ - Monitor * - wintomon(Window w) - { -@@ -2113,6 +2448,22 @@ xerrorstart(Display *dpy, XErrorEvent *ee) - return -1; - } - -+Monitor * -+systraytomon(Monitor *m) { -+ Monitor *t; -+ int i, n; -+ if(!systraypinning) { -+ if(!m) -+ return selmon; -+ return m == selmon ? m : NULL; -+ } -+ for(n = 1, t = mons; t && t->next; n++, t = t->next) ; -+ for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ; -+ if(systraypinningfailfirst && n < systraypinning) -+ return mons; -+ return t; -+} -+ - void - zoom(const Arg *arg) - { diff --git a/suckless/dwm/patches/dwm-uselessgap-6.2.diff b/suckless/dwm/patches/dwm-uselessgap-6.2.diff deleted file mode 100644 index a7847b5e..00000000 --- a/suckless/dwm/patches/dwm-uselessgap-6.2.diff +++ /dev/null @@ -1,81 +0,0 @@ -From 58a5ece9406ca6c90dc362617c065e4aac19417f Mon Sep 17 00:00:00 2001 -From: Cyril Cressent -Date: Wed, 3 Jul 2019 21:33:45 -0700 -Subject: [PATCH] Port the uselessgap patch to 6.2 - ---- - config.def.h | 1 + - dwm.c | 36 ++++++++++++++++++++++++++++++------ - 2 files changed, 31 insertions(+), 6 deletions(-) - -diff --git a/config.def.h b/config.def.h -index 1c0b587..b11471d 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -2,6 +2,7 @@ - - /* appearance */ - static const unsigned int borderpx = 1; /* border pixel of windows */ -+static const unsigned int gappx = 6; /* 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 */ -diff --git a/dwm.c b/dwm.c -index 4465af1..4545e05 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -52,8 +52,8 @@ - #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) - #define LENGTH(X) (sizeof X / sizeof X[0]) - #define MOUSEMASK (BUTTONMASK|PointerMotionMask) --#define WIDTH(X) ((X)->w + 2 * (X)->bw) --#define HEIGHT(X) ((X)->h + 2 * (X)->bw) -+#define WIDTH(X) ((X)->w + 2 * (X)->bw + gappx) -+#define HEIGHT(X) ((X)->h + 2 * (X)->bw + gappx) - #define TAGMASK ((1 << LENGTH(tags)) - 1) - #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) - -@@ -1276,13 +1276,37 @@ void - resizeclient(Client *c, int x, int y, int w, int h) - { - XWindowChanges wc; -+ unsigned int n; -+ unsigned int gapoffset; -+ unsigned int gapincr; -+ Client *nbc; - -- 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; - wc.border_width = c->bw; -+ -+ /* Get number of clients for the selected monitor */ -+ for (n = 0, nbc = nexttiled(selmon->clients); nbc; nbc = nexttiled(nbc->next), n++); -+ -+ /* Do nothing if layout is floating */ -+ if (c->isfloating || selmon->lt[selmon->sellt]->arrange == NULL) { -+ gapincr = gapoffset = 0; -+ } else { -+ /* Remove border and gap if layout is monocle or only one client */ -+ if (selmon->lt[selmon->sellt]->arrange == monocle || n == 1) { -+ gapoffset = 0; -+ gapincr = -2 * borderpx; -+ wc.border_width = 0; -+ } else { -+ gapoffset = gappx; -+ gapincr = 2 * gappx; -+ } -+ } -+ -+ c->oldx = c->x; c->x = wc.x = x + gapoffset; -+ c->oldy = c->y; c->y = wc.y = y + gapoffset; -+ c->oldw = c->w; c->w = wc.width = w - gapincr; -+ c->oldh = c->h; c->h = wc.height = h - gapincr; -+ - XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); - configure(c); - XSync(dpy, False); - -2.22.0 - diff --git a/suckless/dwm/rules.h b/suckless/dwm/rules.h new file mode 100644 index 00000000..c6861501 --- /dev/null +++ b/suckless/dwm/rules.h @@ -0,0 +1,22 @@ +static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + * WM_WINDOW_ROLE(STRING) = role + * _NET_WM_WINDOW_TYPE(ATOM) = wintype + */ + RULE(.class = "discord", .tags = 1 << 8) + RULE(.class = "firefoxdeveloperedition", .tags = 1 << 1) + RULE(.class = "Mailspring", .tags = 1 << 7) + RULE(.class = "Thunderbird", .tags = 1 << 7) + RULE(.class = "st-256color", .tags = 1 << 0) + RULE(.class = "Tor Browser", .tags = 1 << 1) + RULE(.class = "Chromium", .tags = 1 << 1) + RULE(.class = "TelegramDesktop", .tags = 1 << 8) + RULE(.class = "whatsapp-nativefier-d52542", .tags = 1 << 8) + RULE(.class = "Sublime_Text", .tags = 1 << 2) + RULE(.class = "code-oss", .tags = 1 << 2) + RULE(.class = "jetbrains-idea", .tags = 1 << 2) + RULE(.class = "Nemo", .tags = 1 << 3) + RULE(.class = "Spotify", .tags = 1 << 9) +}; diff --git a/suckless/dwm/shiftview.c b/suckless/dwm/shiftview.c deleted file mode 100644 index e82053a4..00000000 --- a/suckless/dwm/shiftview.c +++ /dev/null @@ -1,19 +0,0 @@ -/** Function to shift the current view to the left/right - * - * @param: "arg->i" stores the number of tags to shift right (positive value) - * or left (negative value) - */ -void -shiftview(const Arg *arg) { - Arg shifted; - - if(arg->i > 0) // left circular shift - shifted.ui = (selmon->tagset[selmon->seltags] << arg->i) - | (selmon->tagset[selmon->seltags] >> (LENGTH(tags) - arg->i)); - - else // right circular shift - shifted.ui = selmon->tagset[selmon->seltags] >> (- arg->i) - | selmon->tagset[selmon->seltags] << (LENGTH(tags) + arg->i); - - view(&shifted); -} diff --git a/suckless/dwm/theme.h b/suckless/dwm/theme.h new file mode 100644 index 00000000..ba99364c --- /dev/null +++ b/suckless/dwm/theme.h @@ -0,0 +1,39 @@ +/* appearance */ +static const unsigned int gappx = 6; +static const unsigned int borderpx = 3; /* border pixel of windows */ +static const unsigned int snap = 32; /* snap pixel */ +static const int showbar = 1; /* 0 means no bar */ +static const int user_bh = 27; +static const int bar_height = 27; +static const int topbar = 1; /* 0 means bottom bar */ +static const char *fonts[] = { "CaskaydiaCove Nerd Font:size=10" }; +static const char dmenufont[] = "CaskaydiaCove Nerd Font:size=10"; + +static const int vertpad = 10; /* vertical padding of bar */ +static const int sidepad = 10; /* horizontal padding of bar */ + +static const char fore[] = "#e5e9f0"; +static const char back[] = "#0f111a"; +static const char border[] = "#3a575c"; +static const char col0[] = "#3b4252"; +static const char col1[] = "#bf616a"; /* red */ +static const char col2[] = "#a3be8c"; /* green */ +static const char col3[] = "#ebcb8b"; /* yellow */ +static const char col4[] = "#81a1c1"; /* light_blue */ +static const char col5[] = "#a48ead"; /* puple */ +static const char col6[] = "#88c0d0"; /* blue */ +static const char col7[] = "#e5e9f0"; /* white */ +static const char col8[] = "#4c566a"; /* gray */ + +static char *colors[][ColCount] = { + /* fg bg border float */ + [SchemeNorm] = { fore, back, border, border}, + [SchemeSel] = { fore, back, border, border}, + [SchemeTitleNorm] = { fore, back, border }, + [SchemeTitleSel] = { fore, back, border, border}, + [SchemeTagsNorm] = { fore, back, border, border}, + [SchemeTagsSel] = { back, col1, border, border}, + [SchemeHid] = { back, col4, border, border}, + [SchemeUrg] = { back, col5, border, border}, +}; + diff --git a/suckless/dwm/util.h b/suckless/dwm/util.h index f633b517..30591488 100644 --- a/suckless/dwm/util.h +++ b/suckless/dwm/util.h @@ -1,8 +1,18 @@ /* See LICENSE file for copyright and license details. */ +#ifndef MAX #define MAX(A, B) ((A) > (B) ? (A) : (B)) +#endif +#ifndef MIN #define MIN(A, B) ((A) < (B) ? (A) : (B)) +#endif #define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B)) +#ifdef _DEBUG +#define DEBUG(...) fprintf(stderr, __VA_ARGS__) +#else +#define DEBUG(...) +#endif + void die(const char *fmt, ...); void *ecalloc(size_t nmemb, size_t size); diff --git a/suckless/dwmblocks/.gitignore b/suckless/dwmblocks/.gitignore index 2f27b1b4..c4bb9708 100644 --- a/suckless/dwmblocks/.gitignore +++ b/suckless/dwmblocks/.gitignore @@ -1,3 +1,53 @@ +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex dwmblocks -sigdwmblocks -xgetrootname + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf diff --git a/suckless/dwmblocks/FUNDING.yml b/suckless/dwmblocks/FUNDING.yml new file mode 100644 index 00000000..f8e60767 --- /dev/null +++ b/suckless/dwmblocks/FUNDING.yml @@ -0,0 +1,3 @@ +github: lukesmithxyz +custom: ["https://lukesmith.xyz/donate", "https://paypal.me/lukemsmith", "https://lukesmith.xyz/crypto"] +patreon: lukesmith diff --git a/suckless/dwmblocks/GNUmakefile b/suckless/dwmblocks/GNUmakefile deleted file mode 100644 index 74c7cd0c..00000000 --- a/suckless/dwmblocks/GNUmakefile +++ /dev/null @@ -1,32 +0,0 @@ -#PREFIX := /usr/local -PREFIX := ${HOME}/.local - -CC := gcc -CFLAGS := -O3 -Wall -Wextra -CFLAGSEXTRA := -Wno-missing-field-initializers -Wno-unused-parameter - -X11CFLAGS := $(shell pkg-config --cflags x11) -X11LIBS := $(shell pkg-config --libs x11) - -all: dwmblocks sigdwmblocks - -dwmblocks: dwmblocks.c blocks.h - ${CC} -o $@ ${CFLAGS} ${CFLAGSEXTRA} ${X11CFLAGS} $< ${X11LIBS} - -sigdwmblocks: sigdwmblocks.c - ${CC} -o $@ ${CFLAGS} $< - -xgetrootname: xgetrootname.c - ${CC} -o $@ ${CFLAGS} ${X11CFLAGS} $< ${X11LIBS} - -clean: - rm -f dwmblocks sigdwmblocks - -install: all - install -m 0755 dwmblocks ${DESTDIR}${PREFIX}/dwmblocks - install -m 0755 sigdwmblocks ${DESTDIR}${PREFIX}/sigdwmblocks - -uninstall: - rm -f ${DESTDIR}${PREFIX}/bin/dwmblocks ${DESTDIR}${PREFIX}/sigdwmblocks - -.PHONY: all clean install uninstall diff --git a/suckless/dwmblocks/LICENSE b/suckless/dwmblocks/LICENSE index ac54ae5b..d159169d 100644 --- a/suckless/dwmblocks/LICENSE +++ b/suckless/dwmblocks/LICENSE @@ -1,7 +1,339 @@ -ISC License (ISC) + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 -Copyright 2020 Ashish Kumar Yadav + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. -Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + Preamble -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 2 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/suckless/dwmblocks/Makefile b/suckless/dwmblocks/Makefile new file mode 100644 index 00000000..5cfbb5a8 --- /dev/null +++ b/suckless/dwmblocks/Makefile @@ -0,0 +1,19 @@ +.POSIX: + +PREFIX = /usr/local +CC = gcc + +dwmblocks: dwmblocks.o + $(CC) dwmblocks.o -lX11 -o dwmblocks +dwmblocks.o: dwmblocks.c config.h + $(CC) -c dwmblocks.c +clean: + rm -f *.o *.gch dwmblocks +install: dwmblocks + mkdir -p $(DESTDIR)$(PREFIX)/bin + cp -f dwmblocks $(DESTDIR)$(PREFIX)/bin + chmod 755 $(DESTDIR)$(PREFIX)/bin/dwmblocks +uninstall: + rm -f $(DESTDIR)$(PREFIX)/bin/dwmblocks + +.PHONY: clean install uninstall diff --git a/suckless/dwmblocks/README.md b/suckless/dwmblocks/README.md index 0999105e..7d21e309 100644 --- a/suckless/dwmblocks/README.md +++ b/suckless/dwmblocks/README.md @@ -1,66 +1,44 @@ # dwmblocks -Modular status monitor for dwm written in C with features including -signaling, clickability, cursor hinting and color. - -# Usage - -`dwmblocks [-d ]` +Modular status bar for dwm written in c. # Modifying blocks -Blocks are added and removed by editing the [blocks.h](blocks.h) file. Read it -for more info. - -# Colored output and Clickability +The statusbar is made from text output from commandline programs. Blocks are +added and removed by editing the config.h file. -The patches folder contains two patches for dwm, one for dwm already patched -with systray patch and the other for dwm without systray. One of the patches, -whichever appropriate, is essential for dwmblocks to function properly. It will -add support for colored text, clickability and cursor hinting when hovering on -clickable blocks (inspired by polybar). +# Luke's build -Clickability is inspired by the statuscmd patch for dwm. On clicking on text -corresponding to a clickable block, the program specified to handle clicks for -that block is executed with the first argument specifying which button was -clicked (1 for left, 2 for middle and 3 for right by default). - -Colored output is inspired by the statuscolors patch for dwm. To add colors, -have your programs for the blocks output raw characters from '\x0b' to '\x31'. -'\x0b' in status text switches the active colorscheme to the first one in the -scheme array in dwm and so on. See -[statuscolors patch](https://dwm.suckless.org/patches/statuscolors/) -for more info. Keep in mind that you have to start from '\x0b' instead of '\x01' -as instructed on the page. +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. # Signaling changes -To signal a specific block to update, run `sigdwmblocks []`. -`` is optional and must be an integer. If provided, it is passed as the -first argument to the program specified for updating the block. - -# xgetrootname - -It is a tiny program to get the current root name. May prove helpful in -debugging. +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. -# Installation +For example, the audio module has the update signal 10 by default. Thus, +running `pkill -RTMIN+10 dwmblocks` will update it. -Clone the repository and run `make install clean` after getting in the project -directory. By default the program is installed in `$HOME/.local/bin` -(see [GNUmakefile](GNUmakefile)). If xgetrootname is required run -`make xgetrootname`. +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. -# Acknowledgements +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. -Some ideas and code was taken from other projects. Credits for those go to - +Note that all modules must have different signal numbers. -* torrinfail ([original dwmblocks implementation](https://github.com/torrinfail/dwmblocks)) -* Daniel Bylinka ([statuscmd patch for dwm](https://dwm.suckless.org/patches/statuscmd/)) -* Jeremy Jay ([statuscolors patch for dwm](https://dwm.suckless.org/patches/statuscolors/)) +# Clickable modules -# See also +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. -* [dsblocks](https://github.com/ashish-yadav11/dsblocks) - A clone of this - project with the only difference being that C functions instead of external - programs are used to update blocks and handle clicks. +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). diff --git a/suckless/dwmblocks/blocks.h b/suckless/dwmblocks/blocks.h deleted file mode 100644 index 525dc069..00000000 --- a/suckless/dwmblocks/blocks.h +++ /dev/null @@ -1,33 +0,0 @@ -/* time interval in seconds to sleep before looking for updates in the main loop */ -#define SLEEPINTERVAL 1 - -#define PATH(name) "/home/yigit/.scripts/status-bar/"name - -/* If interval of a block is set to 0, the block will only be updated once at startup. - * If interval is set to a negative value, the block will never be updated in the main loop. - * Set signal to 0 if signalling is not required for the block. - * Signal must be less than 10 for clickable blocks. - * If multiple realtime signals are pending, then the lowest numbered signal is delivered first. */ - -/* pathu - path of the program whose output is to be used for status text - * pathc - path of the program to be executed on clicks */ -static Block blocks[] = { - - { PATH("spotify-bar"), NULL, 5, 6}, - - { PATH("fecha"), NULL, 60, 3}, - - { PATH("arch"), NULL, 3600, 1}, - - { PATH("volume"), NULL, 0, 4}, - - { PATH("cpu-temp"), NULL, 15, 7}, - - { PATH("battery"), NULL, 120, 2}, - - { PATH("red"), NULL, 30, 5}, - - { NULL } /* just to mark the end of the array */ -}; - -static const char *delim = " "; diff --git a/suckless/dwmblocks/config.h b/suckless/dwmblocks/config.h new file mode 100644 index 00000000..11248d97 --- /dev/null +++ b/suckless/dwmblocks/config.h @@ -0,0 +1,20 @@ + +#define PATH(name) "/home/yigit/.scripts/status-bar/"name + +static Block blocks[] = { + + { "", PATH("cpu-temp"), 30, 16}, + { "", PATH("weather"), 60, 15}, + { "", PATH("arch"), 120, 14}, + { "", PATH("network"), 120, 13}, + { "", PATH("battery"), 60, 12}, + { "", PATH("time"), 30, 11}, +}; + +//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/dwmblocks/config.h !cd ~/.local/src/dwmblocks/; sudo make install && { killall -q dwmblocks;setsid dwmblocks & } diff --git a/suckless/dwmblocks/dwmblocks.c b/suckless/dwmblocks/dwmblocks.c index 2b753838..5021af13 100644 --- a/suckless/dwmblocks/dwmblocks.c +++ b/suckless/dwmblocks/dwmblocks.c @@ -1,357 +1,256 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CMDLENGTH 150 -#define STTLENGTH 256 -#define NILL INT_MIN -#define LOCKFILE "/tmp/dwmblocks.pid" +#include +#include +#include +#include +#include +#include +#define LENGTH(X) (sizeof(X) / sizeof (X[0])) +#define CMDLENGTH 50 typedef struct { - char *pathu; - char *pathc; - const int interval; - const int signal; - char cmdoutcur[CMDLENGTH]; - char cmdoutprv[CMDLENGTH]; + char* icon; + char* command; + unsigned int interval; + unsigned int signal; } Block; +char** last_updates; +void sighandler(int num); +void buttonhandler(int sig, siginfo_t *si, void *ucontext); +void replace(char *str, char old, char new); +void remove_all(char *str, char to_remove); +void getcmds(int time); +#ifndef __OpenBSD__ +void getsigcmds(int signal); +void setupsignals(); +void sighandler(int signum); +#endif +int getstatus(char *str, char *last); +void setroot(); +void statusloop(); +void termhandler(int signum); -#include "blocks.h" -static void buttonhandler(int signal, siginfo_t *si, void *ucontext); -static void getcmd(Block *block, int sigval); -static void setroot(); -static void setupsignals(); -static void sighandler(int signal, siginfo_t *si, void *ucontext); -static void statusloop(); -static void termhandler(int signum); -static int updatestatus(); -static void writepid(); +#include "config.h" -static int statuscontinue = 1; -static char statusstr[STTLENGTH]; -static size_t delimlength; static Display *dpy; -static sigset_t blocksigmask; +static int screen; +static Window root; +static char statusbar[LENGTH(blocks)][CMDLENGTH] = {0}; +static char statusstr[2][256]; +static int statusContinue = 1; +static void (*writestatus) () = setroot; -void -buttonhandler(int signal, siginfo_t *si, void *ucontext) +void replace(char *str, char old, char new) { - signal = si->si_value.sival_int >> 8; - switch (fork()) { - case -1: - perror("buttonhandler - fork"); - exit(1); - case 0: - close(ConnectionNumber(dpy)); - for (Block *current = blocks; current->pathu; current++) { - if (current->signal == signal) { - char button[] = { '0' + (si->si_value.sival_int & 0xff), '\0' }; - char *arg[] = { current->pathc, button, NULL }; + int N = strlen(str); + for(int i = 0; i < N; i++) + if(str[i] == old) + str[i] = new; +} - setsid(); - execv(arg[0], arg); - perror("buttonhandler - child - execv"); - _exit(127); - } - } - exit(0); - } +void remove_all(char *str, char to_remove) { + char *read = str; + char *write = str; + while (*read) { + if (*read == to_remove) { + read++; + *write = *read; + } + read++; + write++; + } } -void -getcmd(Block *block, int sigval) +//opens process *cmd and stores output in *output +void getcmd(const Block *block, char* last_update , char *output) { - int fd[2]; - - if (pipe(fd) == -1) { - perror("getcmd - pipe"); - exit(1); - } - switch (fork()) { - case -1: - perror("getcmd - fork"); - exit(1); - case 0: - close(ConnectionNumber(dpy)); - close(fd[0]); - if (fd[1] != STDOUT_FILENO) { - if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) { - perror("getcmd - child - dup2"); - exit(1); - } - close(fd[1]); - } - if (sigval == NILL) { - char *arg[] = { block->pathu, NULL }; - - execv(arg[0], arg); - } else { - char buf[12]; - char *arg[] = { block->pathu, buf, NULL }; + if (block->signal) + { + output[0] = block->signal; + output++; + } + strcpy(output, block->icon); + char *cmd = block->command; + FILE *cmdf = popen(cmd,"r"); + if (!cmdf) + return; + char c; + int i = strlen(block->icon); + fgets(output+i, CMDLENGTH-(strlen(delim)+1), cmdf); + remove_all(output, '\n'); + if(i == strlen(output)) + strcpy(output+i, last_update); + else + strcpy(last_update, output+i); - snprintf(buf, sizeof buf, "%d", sigval); - execv(arg[0], arg); - } - perror("getcmd - child - execv"); - _exit(127); - default: - close(fd[1]); - if (read(fd[0], block->cmdoutcur, CMDLENGTH) == -1) { - perror("getcmd - read"); - exit(1); - } - close(fd[0]); - } + i = strlen(output); + if ((i > 0 && block != &blocks[LENGTH(blocks) - 1])) + strcat(output, delim); + i+=strlen(delim); + output[i++] = '\0'; + pclose(cmdf); } -void -setroot() +void getcmds(int time) { - if (updatestatus()) { - XStoreName(dpy, DefaultRootWindow(dpy), statusstr); - XSync(dpy, False); - } + 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,last_updates[i],statusbar[i]); + } } -void -setupsignals() +#ifndef __OpenBSD__ +void getsigcmds(int signal) { - struct sigaction sa; - - /* to handle HUP, INT and TERM */ - sa.sa_flags = SA_RESTART; - sigemptyset(&sa.sa_mask); - sa.sa_handler = termhandler; - sigaction(SIGHUP, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - sigaction(SIGTERM, &sa, NULL); + const Block *current; + for (int i = 0; i < LENGTH(blocks); i++) + { + current = blocks + i; + if (current->signal == signal) + getcmd(current,last_updates[i],statusbar[i]); + } +} - /* to ignore unused realtime signals */ - // sa.sa_flags = SA_RESTART; - // sigemptyset(&sa.sa_mask); - sa.sa_handler = SIG_IGN; - for (int i = SIGRTMIN + 1; i <= SIGRTMAX; i++) - sigaction(i, &sa, NULL); +void setupsignals() +{ + struct sigaction sa; - /* to prevent forked children from becoming zombies */ - sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART; - // sigemptyset(&sa.sa_mask); - sa.sa_handler = SIG_DFL; - sigaction(SIGCHLD, &sa, NULL); + for(int i = SIGRTMIN; i <= SIGRTMAX; i++) + signal(i, SIG_IGN); - /* to handle signals generated by dwm on click events */ - sa.sa_flags = SA_RESTART | SA_SIGINFO; - // sigemptyset(&sa.sa_mask); - sa.sa_sigaction = buttonhandler; - sigaction(SIGRTMIN, &sa, NULL); + for(int i = 0; i < LENGTH(blocks); i++) + { + if (blocks[i].signal > 0) + { + signal(SIGRTMIN+blocks[i].signal, sighandler); + sigaddset(&sa.sa_mask, SIGRTMIN+blocks[i].signal); + } + } + sa.sa_sigaction = buttonhandler; + sa.sa_flags = SA_SIGINFO; + sigaction(SIGUSR1, &sa, NULL); + struct sigaction sigchld_action = { + .sa_handler = SIG_DFL, + .sa_flags = SA_NOCLDWAIT + }; + sigaction(SIGCHLD, &sigchld_action, NULL); - /* to handle update signals for individual blocks */ - sa.sa_flags |= SA_NODEFER; - sa.sa_mask = blocksigmask; - sa.sa_sigaction = sighandler; - for (Block *current = blocks; current->pathu; current++) - if (current->signal > 0) - sigaction(SIGRTMIN + current->signal, &sa, NULL); } +#endif -void -sighandler(int signal, siginfo_t *si, void *ucontext) +int getstatus(char *str, char *last) { - signal -= SIGRTMIN; - for (Block *current = blocks; current->pathu; current++) - if (current->signal == signal) - getcmd(current, si->si_value.sival_int); - setroot(); + 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 -statusloop() +void setroot() { - int i; - - /* first run */ - sigprocmask(SIG_BLOCK, &blocksigmask, NULL); - for (Block *current = blocks; current->pathu; current++) - if (current->interval >= 0) - getcmd(current, NILL); - setroot(); - sigprocmask(SIG_UNBLOCK, &blocksigmask, NULL); - sleep(SLEEPINTERVAL); - i = SLEEPINTERVAL; - /* main loop */ - while (statuscontinue) { - sigprocmask(SIG_BLOCK, &blocksigmask, NULL); - for (Block *current = blocks; current->pathu; current++) - if (current->interval > 0 && i % current->interval == 0) - getcmd(current, NILL); - setroot(); - sigprocmask(SIG_UNBLOCK, &blocksigmask, NULL); - sleep(SLEEPINTERVAL); - i += SLEEPINTERVAL; - } + 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 -termhandler(int signum) +void pstdout() { - statuscontinue = 0; + if (!getstatus(statusstr[0], statusstr[1]))//Only write out if text has changed. + return; + printf("%s\n",statusstr[0]); + fflush(stdout); } -/* returns whether block outputs have changed and updates statusstr if they have */ -int -updatestatus() -{ - char *s = statusstr; - char *c, *p; /* for cmdoutcur and cmdoutprv */ - const char *d; /* for delimiter */ - Block *current = blocks; - /* checking half of the function */ - /* find the first non-empty block */ - for (;; current++) { - /* all blocks are empty */ - if (!current->pathu) - return 0; - /* contents of the current block just changed */ - if (*current->cmdoutcur != *current->cmdoutprv) - goto update0; - /* no delimiter before the first non-empty block */ - if (*current->cmdoutcur != '\n' && *current->cmdoutcur != '\0') - goto skipdelimc; - } - /* main loop */ - for (; current->pathu; current++) { - /* contents of the current block just changed */ - if (*current->cmdoutcur != *current->cmdoutprv) - goto update1; - /* delimiter handler */ - /* current block is non-empty */ - if (*current->cmdoutcur != '\n' && *current->cmdoutcur != '\0') - s += delimlength; - /* skip over empty blocks */ - else - continue; -skipdelimc: - /* checking for the first byte has been done */ - c = current->cmdoutcur + 1, p = current->cmdoutprv + 1; - for (; *c != '\n' && *c != '\0'; c++, p++) - /* contents of the current block just changed */ - if (*c != *p) { - s += c - current->cmdoutcur; - goto update2; - } - s += c - current->cmdoutcur; - /* byte containing info about signal number for the block */ - if (current->pathc && current->signal) - s++; - } - return 0; +void statusloop() +{ +#ifndef __OpenBSD__ + setupsignals(); +#endif + last_updates = malloc(sizeof(char*) * LENGTH(blocks)); + for(int i = 0; i < LENGTH(blocks); i++) { + last_updates[i] = malloc(sizeof(char) * CMDLENGTH); + strcpy(last_updates[i],""); + } + int i = 0; + getcmds(-1); + while(statusContinue) + { + getcmds(i); + writestatus(); + sleep(1.0); + i++; + } +} - /* updating half of the function */ - /* find the first non-empty block */ - for (;; current++) { - /* all blocks are empty */ - if (!current->pathu) - return 1; -update0: - /* skip delimiter before the first non-empty block */ - if (*current->cmdoutcur != '\n' && *current->cmdoutcur != '\0') - goto skipdelimu; - *current->cmdoutprv = *current->cmdoutcur; - } - /* main loop */ - for (; current->pathu; current++) { -update1: - /* delimiter handler */ - /* current block is non-empty */ - if (*current->cmdoutcur != '\n' && *current->cmdoutcur != '\0') { - d = delim; - while (*d != '\0') - *(s++) = *(d++); - *(s++) = '\n'; /* to mark the end of delimiter */ - /* skip over empty blocks */ - } else { - *current->cmdoutprv = *current->cmdoutcur; - continue; - } -skipdelimu: - c = current->cmdoutcur, p = current->cmdoutprv; -update2: - do { - *(s++) = *c; - *p = *c; - c++, p++; - } while (*c != '\n' && *c != '\0'); - if (current->pathc && current->signal) - *(s++) = current->signal; - } - *s = '\0'; - return 1; +#ifndef __OpenBSD__ +void sighandler(int signum) +{ + getsigcmds(signum-SIGRTMIN); + writestatus(); } -void -writepid() +void buttonhandler(int sig, siginfo_t *si, void *ucontext) { - int fd; - struct flock fl; + char button[2] = {'0' + si->si_value.sival_int & 0xff, '\0'}; + pid_t process_id = getpid(); + sig = si->si_value.sival_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); + } +} + +#endif - fd = open(LOCKFILE, O_RDWR|O_CREAT, 0644); - if (fd == -1) { - perror("writepid - fd"); - exit(1); - } - fl.l_type = F_WRLCK; - fl.l_start = 0; - fl.l_whence = SEEK_SET; - fl.l_len = 0; - if (fcntl(fd, F_SETLK, &fl) == -1) { - if (errno == EACCES || errno == EAGAIN) { - fputs("Error: another instance of dwmblocks is already running.\n", stderr); - exit(2); - } - perror("writepid - fcntl"); - exit(1); - } - if (ftruncate(fd, 0) == -1) { - perror("writepid - ftruncate"); - exit(1); - } - if (dprintf(fd, "%ld", (long)getpid()) < 0) { - perror("writepid - dprintf"); - exit(1); - } +void termhandler(int signum) +{ + for(int i = 0; i < LENGTH(blocks); i++) { + free(last_updates[i]); + } + free(last_updates); + statusContinue = 0; + exit(0); } -int -main(int argc, char *argv[]) +int main(int argc, char** argv) { - writepid(); - if (argc > 2) - if (strcmp(argv[1], "-d") == 0) - delim = argv[2]; - delimlength = strlen(delim) + 1; - if (!(dpy = XOpenDisplay(NULL))) { - fputs("Error: could not open display.\n", stderr); - return 1; - } - sigemptyset(&blocksigmask); - sigaddset(&blocksigmask, SIGHUP); - sigaddset(&blocksigmask, SIGINT); - sigaddset(&blocksigmask, SIGTERM); - for (Block *current = blocks; current->pathu; current++) - if (current->signal > 0) - sigaddset(&blocksigmask, SIGRTMIN + current->signal); - setupsignals(); - statusloop(); - unlink(LOCKFILE); - XStoreName(dpy, DefaultRootWindow(dpy), ""); - XCloseDisplay(dpy); - return 0; + 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(); } diff --git a/suckless/dwmblocks/patches/dwmblocks-statuscmd-fork.diff b/suckless/dwmblocks/patches/dwmblocks-statuscmd-fork.diff new file mode 100644 index 00000000..1ae7d7a1 --- /dev/null +++ b/suckless/dwmblocks/patches/dwmblocks-statuscmd-fork.diff @@ -0,0 +1,77 @@ +diff --git a/dwmblocks.c b/dwmblocks.c +index 7d7a564..e2c5dd0 100644 +--- a/dwmblocks.c ++++ b/dwmblocks.c +@@ -34,8 +34,6 @@ static int screen; + static Window root; + static char statusbar[LENGTH(blocks)][CMDLENGTH] = {0}; + static char statusstr[2][256]; +-static char exportstring[CMDLENGTH + 22] = "export BLOCK_BUTTON=-;"; +-static int button = 0; + static int statusContinue = 1; + static void (*writestatus) () = setroot; + +@@ -55,21 +53,8 @@ void getcmd(const Block *block, char *output) + output[0] = block->signal; + output++; + } +- char* cmd; +- FILE *cmdf; +- if (button) +- { +- cmd = strcat(exportstring, block->command); +- cmd[20] = '0' + button; +- button = 0; +- cmdf = popen(cmd,"r"); +- cmd[22] = '\0'; +- } +- else +- { +- cmd = block->command; +- cmdf = popen(cmd,"r"); +- } ++ char *cmd = block->command; ++ FILE *cmdf = popen(cmd,"r"); + if (!cmdf) + return; + fgets(output, CMDLENGTH, cmdf); +@@ -117,6 +102,7 @@ void setupsignals() + sa.sa_sigaction = buttonhandler; + sa.sa_flags = SA_SIGINFO; + sigaction(SIGUSR1, &sa, NULL); ++ signal(SIGCHLD, SIG_IGN); + + } + #endif +@@ -179,9 +165,29 @@ void sighandler(int signum) + + void buttonhandler(int sig, siginfo_t *si, void *ucontext) + { +- button = si->si_value.sival_int & 0xff; +- getsigcmds(si->si_value.sival_int >> 8); ++ int button = si->si_value.sival_int & 0xff; ++ sig = si->si_value.sival_int >> 8; ++ getsigcmds(sig); + writestatus(); ++ if (fork() == 0) ++ { ++ static char exportstring[CMDLENGTH + 22] = "export BLOCK_BUTTON=-;"; ++ const Block *current; ++ int i; ++ for (i = 0; i < LENGTH(blocks); i++) ++ { ++ current = blocks + i; ++ if (current->signal == sig) ++ break; ++ } ++ char *cmd = strcat(exportstring, blocks[i].command); ++ cmd[20] = '0' + button; ++ char *command[] = { "/bin/sh", "-c", cmd, NULL }; ++ setsid(); ++ execvp(command[0], command); ++ exit(EXIT_SUCCESS); ++ cmd[22] = '\0'; ++ } + } + + #endif diff --git a/suckless/dwmblocks/patches/dwmblocks-statuscmd-signal.diff b/suckless/dwmblocks/patches/dwmblocks-statuscmd-signal.diff new file mode 100644 index 00000000..c2092e77 --- /dev/null +++ b/suckless/dwmblocks/patches/dwmblocks-statuscmd-signal.diff @@ -0,0 +1,93 @@ +diff --git a/dwmblocks.c b/dwmblocks.c +index 88bdfb0..7bd14df 100644 +--- a/dwmblocks.c ++++ b/dwmblocks.c +@@ -14,6 +14,7 @@ typedef struct { + unsigned int signal; + } Block; + void sighandler(int num); ++void buttonhandler(int sig, siginfo_t *si, void *ucontext); + void replace(char *str, char old, char new); + void getcmds(int time); + #ifndef __OpenBSD__ +@@ -34,6 +35,8 @@ static int screen; + static Window root; + static char statusbar[LENGTH(blocks)][CMDLENGTH] = {0}; + static char statusstr[2][256]; ++static char exportstring[CMDLENGTH + 16] = "export BUTTON=-;"; ++static int button = 0; + static int statusContinue = 1; + static void (*writestatus) () = setroot; + +@@ -48,16 +51,34 @@ void replace(char *str, char old, char new) + //opens process *cmd and stores output in *output + void getcmd(const Block *block, char *output) + { ++ if (block->signal) ++ { ++ output[0] = block->signal; ++ output++; ++ } + strcpy(output, block->icon); +- char *cmd = block->command; +- FILE *cmdf = popen(cmd,"r"); ++ char* cmd; ++ FILE *cmdf; ++ if (button) ++ { ++ cmd = strcat(exportstring, block->command); ++ cmd[14] = '0' + button; ++ button = 0; ++ cmdf = popen(cmd,"r"); ++ cmd[16] = '\0'; ++ } ++ else ++ { ++ cmd = block->command; ++ cmdf = popen(cmd,"r"); ++ } + if (!cmdf) + return; + char c; + int i = strlen(block->icon); + fgets(output+i, CMDLENGTH-i, cmdf); + i = strlen(output); +- if (delim != '\0' && --i) ++ if (delim != '\0' && i) + output[i++] = delim; + output[i++] = '\0'; + pclose(cmdf); +@@ -88,11 +106,18 @@ void getsigcmds(int signal) + + void setupsignals() + { ++ struct sigaction sa; + for(int i = 0; i < LENGTH(blocks); i++) + { + if (blocks[i].signal > 0) ++ { + signal(SIGRTMIN+blocks[i].signal, sighandler); ++ sigaddset(&sa.sa_mask, SIGRTMIN+blocks[i].signal); ++ } + } ++ sa.sa_sigaction = buttonhandler; ++ sa.sa_flags = SA_SIGINFO; ++ sigaction(SIGUSR1, &sa, NULL); + + } + #endif +@@ -152,6 +177,14 @@ void sighandler(int signum) + getsigcmds(signum-SIGRTMIN); + writestatus(); + } ++ ++void buttonhandler(int sig, siginfo_t *si, void *ucontext) ++{ ++ button = si->si_value.sival_int & 0xff; ++ getsigcmds(si->si_value.sival_int >> 8); ++ writestatus(); ++} ++ + #endif + + void termhandler(int signum) diff --git a/suckless/dwmblocks/sigdwmblocks.c b/suckless/dwmblocks/sigdwmblocks.c deleted file mode 100644 index 5d5fb80e..00000000 --- a/suckless/dwmblocks/sigdwmblocks.c +++ /dev/null @@ -1,76 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#define LOCKFILE "/tmp/dwmblocks.pid" - -void -sendsignal(int signum, union sigval sv) -{ - int fd; - struct flock fl; - - fd = open(LOCKFILE, O_RDONLY); - if (fd == -1) { - if (errno == ENOENT) { - fputs("Error: no running instance of dwmblocks.\n", stderr); - exit(2); - } - perror("sendsignal - fd"); - exit(1); - } - fl.l_type = F_WRLCK; - fl.l_start = 0; - fl.l_whence = SEEK_SET; - fl.l_len = 0; - if (fcntl(fd, F_GETLK, &fl) == -1) { - perror("sendsignal - fcntl"); - exit(1); - } - if (fl.l_type == F_UNLCK) { - fputs("Error: no running instance of dwmblocks.\n", stderr); - exit(2); - } - if (sigqueue(fl.l_pid, signum, sv) == -1) { - if (errno == EINVAL) { - fputs("Error: invalid signal provided in argument.\n", stderr); - exit(3); - } else if (errno == ESRCH) { - fputs("Error: no running instance of dwmblocks.\n", stderr); - exit(2); - } else { - perror("sendsignal - sigqueue"); - exit(1); - } - } -} - -int -main(int argc, char *argv[]) -{ - if (argc > 1) { - int signal; - union sigval sv; - - if (sscanf(argv[1], "%d", &signal) == 1 && - signal > 0 && (signal += SIGRTMIN) <= SIGRTMAX) { - if (argc == 2) { - sv.sival_int = INT_MIN; - sendsignal(signal, sv); - return 0; - } else if (argc == 3 && - sscanf(argv[2], "%d", &(sv.sival_int)) == 1) { - sendsignal(signal, sv); - return 0; - } - } - } - - fprintf(stderr, "Usage: %s []\n", argv[0]); - return 3; -} diff --git a/suckless/dwmblocks/xgetrootname.c b/suckless/dwmblocks/xgetrootname.c deleted file mode 100644 index e04154c0..00000000 --- a/suckless/dwmblocks/xgetrootname.c +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -int -main() -{ - Display *dpy; - char *name; - - if (!(dpy = XOpenDisplay(NULL))) { - fputs("Error: could not open display.\n", stderr); - return 1; - } - if (XFetchName(dpy, DefaultRootWindow(dpy), &name) && name[0]) - printf("%s\n", name); - else - puts("No name has been set for the root window."); - XFree(name); - XCloseDisplay(dpy); - return 0; -} diff --git a/xorg/Xresources b/xorg/Xresources new file mode 100644 index 00000000..15107647 --- /dev/null +++ b/xorg/Xresources @@ -0,0 +1,23 @@ +/* Copyright © Blacksuan19 @ 2020 + Part of Material Ocean Theme + Licensed Under GNU's GPL3 +*/ + +*background: #0f111a +*foreground: #e5e9f0 +*color0: #3B4252 +*color1: #BF616A +*color2: #A3BE8C +*color3: #EBCB8B +*color4: #81A1C1 +*color5: #B48EAD +*color6: #88C0D0 +*color7: #E5E9F0 +*color8: #4C566A +*color9: #BF616A +*color10: #A3BE8C +*color11: #EBCB8B +*color12: #81A1C1 +*color13: #B48EAD +*color14: #88C0D0 +*color15: #B48EAD diff --git a/xorg/xinitrc b/xorg/xinitrc index e07a1bf9..515faf59 100755 --- a/xorg/xinitrc +++ b/xorg/xinitrc @@ -27,4 +27,4 @@ export AWT_TOOLKIT=MToolkit if [ -f ~/.xmodmap ]; then xmodmap ~/.xmodmap fi -exec dwm +exec dwm > /tmp/dwm.log 2> /tmp/dwm.err