From 0b274c969e824b4bcf328e3272b8894143f3a683 Mon Sep 17 00:00:00 2001 From: iceyrazor Date: Sun, 24 Nov 2024 04:50:59 -0600 Subject: [PATCH] reinit 3. git reset --hard was not right. thanks ai --- .Xresources | 82 + .bash_profile | 18 + .bashrc | 10 + .../awesome/iceys-theme/layouts/cornerne.png | Bin 0 -> 272 bytes .../awesome/iceys-theme/layouts/cornernew.png | Bin 0 -> 272 bytes .../awesome/iceys-theme/layouts/cornernw.png | Bin 0 -> 263 bytes .../awesome/iceys-theme/layouts/cornernww.png | Bin 0 -> 264 bytes .../awesome/iceys-theme/layouts/cornerse.png | Bin 0 -> 264 bytes .../awesome/iceys-theme/layouts/cornersew.png | Bin 0 -> 264 bytes .../awesome/iceys-theme/layouts/cornersw.png | Bin 0 -> 263 bytes .../awesome/iceys-theme/layouts/cornersww.png | Bin 0 -> 264 bytes .../awesome/iceys-theme/layouts/dwindle.png | Bin 0 -> 320 bytes .../awesome/iceys-theme/layouts/dwindlew.png | Bin 0 -> 320 bytes .config/awesome/iceys-theme/layouts/fairh.png | Bin 0 -> 245 bytes .../awesome/iceys-theme/layouts/fairhw.png | Bin 0 -> 245 bytes .config/awesome/iceys-theme/layouts/fairv.png | Bin 0 -> 246 bytes .../awesome/iceys-theme/layouts/fairvw.png | Bin 0 -> 246 bytes .../awesome/iceys-theme/layouts/floating.png | Bin 0 -> 282 bytes .../awesome/iceys-theme/layouts/floatingw.png | Bin 0 -> 282 bytes .../iceys-theme/layouts/fullscreen.png | Bin 0 -> 866 bytes .../iceys-theme/layouts/fullscreenw.png | Bin 0 -> 865 bytes .../awesome/iceys-theme/layouts/magnifier.png | Bin 0 -> 345 bytes .../iceys-theme/layouts/magnifierw.png | Bin 0 -> 345 bytes .config/awesome/iceys-theme/layouts/max.png | Bin 0 -> 574 bytes .config/awesome/iceys-theme/layouts/maxw.png | Bin 0 -> 581 bytes .../awesome/iceys-theme/layouts/spiral.png | Bin 0 -> 328 bytes .../awesome/iceys-theme/layouts/spiralw.png | Bin 0 -> 328 bytes .config/awesome/iceys-theme/layouts/tile.png | Bin 0 -> 265 bytes .../iceys-theme/layouts/tilebottom.png | Bin 0 -> 264 bytes .../iceys-theme/layouts/tilebottomw.png | Bin 0 -> 264 bytes .../awesome/iceys-theme/layouts/tileleft.png | Bin 0 -> 266 bytes .../awesome/iceys-theme/layouts/tileleftw.png | Bin 0 -> 266 bytes .../awesome/iceys-theme/layouts/tiletop.png | Bin 0 -> 260 bytes .../awesome/iceys-theme/layouts/tiletopw.png | Bin 0 -> 265 bytes .config/awesome/iceys-theme/layouts/tilew.png | Bin 0 -> 265 bytes .config/awesome/iceys-theme/submenu.png | Bin 0 -> 440 bytes .../awesome/iceys-theme/taglist/squarefw.png | Bin 0 -> 187 bytes .../awesome/iceys-theme/taglist/squarew.png | Bin 0 -> 193 bytes .config/awesome/iceys-theme/theme.lua | 147 + .../iceys-theme/titlebar/close_focus.png | Bin 0 -> 966 bytes .../iceys-theme/titlebar/close_normal.png | Bin 0 -> 966 bytes .../titlebar/floating_focus_active.png | Bin 0 -> 386 bytes .../titlebar/floating_focus_inactive.png | Bin 0 -> 237 bytes .../titlebar/floating_normal_active.png | Bin 0 -> 386 bytes .../titlebar/floating_normal_inactive.png | Bin 0 -> 237 bytes .../titlebar/maximized_focus_active.png | Bin 0 -> 480 bytes .../titlebar/maximized_focus_inactive.png | Bin 0 -> 452 bytes .../titlebar/maximized_normal_active.png | Bin 0 -> 480 bytes .../titlebar/maximized_normal_inactive.png | Bin 0 -> 452 bytes .../iceys-theme/titlebar/minimize_focus.png | Bin 0 -> 234 bytes .../iceys-theme/titlebar/minimize_normal.png | Bin 0 -> 225 bytes .../titlebar/ontop_focus_active.png | Bin 0 -> 467 bytes .../titlebar/ontop_focus_inactive.png | Bin 0 -> 604 bytes .../titlebar/ontop_normal_active.png | Bin 0 -> 467 bytes .../titlebar/ontop_normal_inactive.png | Bin 0 -> 604 bytes .../titlebar/sticky_focus_active.png | Bin 0 -> 654 bytes .../titlebar/sticky_focus_inactive.png | Bin 0 -> 758 bytes .../titlebar/sticky_normal_active.png | Bin 0 -> 654 bytes .../titlebar/sticky_normal_inactive.png | Bin 0 -> 758 bytes .config/awesome/rc.bak2.lua | 580 ++++ .config/awesome/rc.lua | 652 +++++ .config/dwm/autostart.sh | 35 + .config/dwm/newsboat-fetch.sh | 15 + .config/gtk-3.0/settings.ini | 3 + .config/lf/lfrc | 140 + .config/nvim/.luarc.json | 13 + .config/nvim/after/plugin/harpoon.lua | 11 + .config/nvim/after/plugin/lsp.lua | 45 + .config/nvim/after/plugin/telescope.lua | 6 + .config/nvim/after/plugin/undotree.lua | 1 + .config/nvim/custom-lsp/.luarc.json | 3 + .config/nvim/init.lua | 1 + .config/nvim/lua/yourmom/init.lua | 39 + .config/nvim/lua/yourmom/packer.lua | 55 + .config/nvim/lua/yourmom/remap.lua | 58 + .config/nvim/spell/en.utf-8.add | 21 + .config/nvim/spell/en.utf-8.add.spl | Bin 0 -> 253 bytes .config/picom.conf | 445 +++ .config/rofi/config.rasi | 5 + .config/screenkey.json | 32 + .gitmodules | 3 + .gtkrc-2.0 | 13 + .profile | 93 + .surf/styles/default.css | 16 + .urlview | 29 + .vimrc | 78 + .wezterm.lua | 50 + .zshrc | 22 + LICENSE | 21 + README.md | 65 + .../suckless/dmenu-5.2/LICENSE | 30 + .../suckless/dmenu-5.2/Makefile | 64 + .../manual-programs/suckless/dmenu-5.2/README | 24 + .../manual-programs/suckless/dmenu-5.2/arg.h | 49 + .../suckless/dmenu-5.2/config.h | 23 + .../suckless/dmenu-5.2/config.mk | 32 + .../manual-programs/suckless/dmenu-5.2/dmenu | Bin 0 -> 42664 bytes .../suckless/dmenu-5.2/dmenu.1 | 194 ++ .../suckless/dmenu-5.2/dmenu.c | 791 +++++ .../suckless/dmenu-5.2/dmenu.o | Bin 0 -> 31672 bytes .../suckless/dmenu-5.2/dmenu_path | 13 + .../suckless/dmenu-5.2/dmenu_run | 2 + .../manual-programs/suckless/dmenu-5.2/drw.c | 450 +++ .../manual-programs/suckless/dmenu-5.2/drw.h | 58 + .../manual-programs/suckless/dmenu-5.2/drw.o | Bin 0 -> 11000 bytes .../manual-programs/suckless/dmenu-5.2/stest | Bin 0 -> 16432 bytes .../suckless/dmenu-5.2/stest.1 | 90 + .../suckless/dmenu-5.2/stest.c | 109 + .../suckless/dmenu-5.2/stest.o | Bin 0 -> 5256 bytes .../manual-programs/suckless/dmenu-5.2/util.c | 36 + .../manual-programs/suckless/dmenu-5.2/util.h | 8 + .../manual-programs/suckless/dmenu-5.2/util.o | Bin 0 -> 2224 bytes .../manual-programs/suckless/dwm-bak/LICENSE | 37 + .../manual-programs/suckless/dwm-bak/Makefile | 51 + stuff/manual-programs/suckless/dwm-bak/README | 48 + .../suckless/dwm-bak/awesome-glyphs.txt | 34 + .../suckless/dwm-bak/config.def.h.orig | 142 + .../manual-programs/suckless/dwm-bak/config.h | 146 + .../suckless/dwm-bak/config.mk | 38 + stuff/manual-programs/suckless/dwm-bak/drw.c | 435 +++ stuff/manual-programs/suckless/dwm-bak/drw.h | 57 + stuff/manual-programs/suckless/dwm-bak/drw.o | Bin 0 -> 10488 bytes stuff/manual-programs/suckless/dwm-bak/dwm | Bin 0 -> 74816 bytes .../dwm-autostart-20161205-bb3bd6f.diff | 39 + .../suckless/dwm-bak/dwm-fullgaps-6.2.diff | 95 + .../suckless/dwm-bak/dwm-systray-6.2.diff | 746 +++++ stuff/manual-programs/suckless/dwm-bak/dwm.1 | 176 ++ stuff/manual-programs/suckless/dwm-bak/dwm.c | 2524 ++++++++++++++++ .../suckless/dwm-bak/dwm.c.orig | 2516 ++++++++++++++++ stuff/manual-programs/suckless/dwm-bak/dwm.o | Bin 0 -> 69016 bytes .../manual-programs/suckless/dwm-bak/dwm.png | Bin 0 -> 373 bytes .../suckless/dwm-bak/dwmstatus/LICENSE | 21 + .../suckless/dwm-bak/dwmstatus/Makefile | 49 + .../suckless/dwm-bak/dwmstatus/config.mk | 30 + .../dwm-bak/dwmstatus/dwmstatus-temperature.c | 15 + .../suckless/dwm-bak/dwmstatus/dwmstatus.c | 227 ++ .../dwm-bak/dwmstatus/new-acpi-battery.c | 55 + stuff/manual-programs/suckless/dwm-bak/endx | 5 + .../suckless/dwm-bak/shiftview.c | 19 + .../suckless/dwm-bak/transient.c | 42 + stuff/manual-programs/suckless/dwm-bak/util.c | 35 + stuff/manual-programs/suckless/dwm-bak/util.h | 8 + stuff/manual-programs/suckless/dwm-bak/util.o | Bin 0 -> 2224 bytes stuff/manual-programs/suckless/dwm/LICENSE | 37 + stuff/manual-programs/suckless/dwm/Makefile | 51 + stuff/manual-programs/suckless/dwm/README | 48 + .../suckless/dwm/awesome-glyphs.txt | 34 + .../suckless/dwm/config.def.h.orig | 146 + stuff/manual-programs/suckless/dwm/config.h | 151 + stuff/manual-programs/suckless/dwm/config.mk | 38 + stuff/manual-programs/suckless/dwm/drw.c | 435 +++ stuff/manual-programs/suckless/dwm/drw.h | 57 + stuff/manual-programs/suckless/dwm/drw.o | Bin 0 -> 10408 bytes stuff/manual-programs/suckless/dwm/dwm | Bin 0 -> 74704 bytes .../dwm/dwm-autostart-20161205-bb3bd6f.diff | 39 + .../suckless/dwm/dwm-bottomstack-6.1.diff | 101 + .../suckless/dwm/dwm-fullgaps-6.2.diff | 95 + .../suckless/dwm/dwm-systray-6.2.diff | 746 +++++ stuff/manual-programs/suckless/dwm/dwm.1 | 176 ++ stuff/manual-programs/suckless/dwm/dwm.c | 2588 +++++++++++++++++ stuff/manual-programs/suckless/dwm/dwm.c.orig | 2516 ++++++++++++++++ stuff/manual-programs/suckless/dwm/dwm.o | Bin 0 -> 69688 bytes stuff/manual-programs/suckless/dwm/dwm.png | Bin 0 -> 373 bytes .../suckless/dwm/dwmstatus/LICENSE | 21 + .../suckless/dwm/dwmstatus/Makefile | 49 + .../suckless/dwm/dwmstatus/config.mk | 30 + .../dwm/dwmstatus/dwmstatus-temperature.c | 15 + .../suckless/dwm/dwmstatus/dwmstatus.c | 227 ++ .../suckless/dwm/dwmstatus/new-acpi-battery.c | 55 + stuff/manual-programs/suckless/dwm/endx | 5 + .../manual-programs/suckless/dwm/shiftview.c | 19 + .../manual-programs/suckless/dwm/transient.c | 42 + stuff/manual-programs/suckless/dwm/util.c | 35 + stuff/manual-programs/suckless/dwm/util.h | 8 + stuff/manual-programs/suckless/dwm/util.o | Bin 0 -> 2224 bytes stuff/manual-programs/suckless/surf/FAQ.md | 10 + stuff/manual-programs/suckless/surf/LICENSE | 57 + stuff/manual-programs/suckless/surf/Makefile | 76 + stuff/manual-programs/suckless/surf/README | 40 + stuff/manual-programs/suckless/surf/TODO.md | 10 + stuff/manual-programs/suckless/surf/arg.h | 48 + stuff/manual-programs/suckless/surf/common.h | 1 + .../suckless/surf/config.def.h | 205 ++ .../suckless/surf/config.def.h.orig | 200 ++ stuff/manual-programs/suckless/surf/config.h | 205 ++ stuff/manual-programs/suckless/surf/config.mk | 32 + stuff/manual-programs/suckless/surf/surf | Bin 0 -> 75024 bytes .../surf/surf-modal-20190209-d068a38.diff | 134 + .../suckless/surf/surf-open.sh | 32 + .../surf-uri-aliases-20220930-089272b.diff | 58 + stuff/manual-programs/suckless/surf/surf.1 | 305 ++ stuff/manual-programs/suckless/surf/surf.c | 2155 ++++++++++++++ .../manual-programs/suckless/surf/surf.c.orig | 2143 ++++++++++++++ stuff/manual-programs/suckless/surf/surf.o | Bin 0 -> 72976 bytes stuff/manual-programs/suckless/surf/surf.png | Bin 0 -> 240 bytes .../suckless/surf/webext-surf.c | 166 ++ .../suckless/surf/webext-surf.o | Bin 0 -> 6560 bytes .../suckless/surf/webext-surf.so | Bin 0 -> 16728 bytes stuff/scripts/system/backup/backup.sh | 30 + stuff/scripts/system/backup/copy-to-git.sh | 21 + stuff/scripts/system/bri.sh | 1 + stuff/scripts/system/math.sh | 13 + stuff/scripts/system/neoboot.sh | 28 + stuff/scripts/system/restart-pipe.sh | 1 + stuff/scripts/system/set-pri-java.sh | 1 + stuff/scripts/system/stbar/config.txt | 2 + stuff/scripts/system/stbar/killbar.sh | 10 + stuff/scripts/system/stbar/stbar-awesome.sh | 81 + stuff/scripts/system/stbar/stbar.sh | 84 + stuff/scripts/system/stbar/weth_str.txt | 0 stuff/scripts/system/url-handler.sh | 18 + 211 files changed, 26301 insertions(+) create mode 100755 .Xresources create mode 100644 .bash_profile create mode 100755 .bashrc create mode 100644 .config/awesome/iceys-theme/layouts/cornerne.png create mode 100644 .config/awesome/iceys-theme/layouts/cornernew.png create mode 100644 .config/awesome/iceys-theme/layouts/cornernw.png create mode 100644 .config/awesome/iceys-theme/layouts/cornernww.png create mode 100644 .config/awesome/iceys-theme/layouts/cornerse.png create mode 100644 .config/awesome/iceys-theme/layouts/cornersew.png create mode 100644 .config/awesome/iceys-theme/layouts/cornersw.png create mode 100644 .config/awesome/iceys-theme/layouts/cornersww.png create mode 100644 .config/awesome/iceys-theme/layouts/dwindle.png create mode 100644 .config/awesome/iceys-theme/layouts/dwindlew.png create mode 100644 .config/awesome/iceys-theme/layouts/fairh.png create mode 100644 .config/awesome/iceys-theme/layouts/fairhw.png create mode 100644 .config/awesome/iceys-theme/layouts/fairv.png create mode 100644 .config/awesome/iceys-theme/layouts/fairvw.png create mode 100644 .config/awesome/iceys-theme/layouts/floating.png create mode 100644 .config/awesome/iceys-theme/layouts/floatingw.png create mode 100644 .config/awesome/iceys-theme/layouts/fullscreen.png create mode 100644 .config/awesome/iceys-theme/layouts/fullscreenw.png create mode 100644 .config/awesome/iceys-theme/layouts/magnifier.png create mode 100644 .config/awesome/iceys-theme/layouts/magnifierw.png create mode 100644 .config/awesome/iceys-theme/layouts/max.png create mode 100644 .config/awesome/iceys-theme/layouts/maxw.png create mode 100644 .config/awesome/iceys-theme/layouts/spiral.png create mode 100644 .config/awesome/iceys-theme/layouts/spiralw.png create mode 100644 .config/awesome/iceys-theme/layouts/tile.png create mode 100644 .config/awesome/iceys-theme/layouts/tilebottom.png create mode 100644 .config/awesome/iceys-theme/layouts/tilebottomw.png create mode 100644 .config/awesome/iceys-theme/layouts/tileleft.png create mode 100644 .config/awesome/iceys-theme/layouts/tileleftw.png create mode 100644 .config/awesome/iceys-theme/layouts/tiletop.png create mode 100644 .config/awesome/iceys-theme/layouts/tiletopw.png create mode 100644 .config/awesome/iceys-theme/layouts/tilew.png create mode 100644 .config/awesome/iceys-theme/submenu.png create mode 100644 .config/awesome/iceys-theme/taglist/squarefw.png create mode 100644 .config/awesome/iceys-theme/taglist/squarew.png create mode 100644 .config/awesome/iceys-theme/theme.lua create mode 100644 .config/awesome/iceys-theme/titlebar/close_focus.png create mode 100644 .config/awesome/iceys-theme/titlebar/close_normal.png create mode 100644 .config/awesome/iceys-theme/titlebar/floating_focus_active.png create mode 100644 .config/awesome/iceys-theme/titlebar/floating_focus_inactive.png create mode 100644 .config/awesome/iceys-theme/titlebar/floating_normal_active.png create mode 100644 .config/awesome/iceys-theme/titlebar/floating_normal_inactive.png create mode 100644 .config/awesome/iceys-theme/titlebar/maximized_focus_active.png create mode 100644 .config/awesome/iceys-theme/titlebar/maximized_focus_inactive.png create mode 100644 .config/awesome/iceys-theme/titlebar/maximized_normal_active.png create mode 100644 .config/awesome/iceys-theme/titlebar/maximized_normal_inactive.png create mode 100644 .config/awesome/iceys-theme/titlebar/minimize_focus.png create mode 100644 .config/awesome/iceys-theme/titlebar/minimize_normal.png create mode 100644 .config/awesome/iceys-theme/titlebar/ontop_focus_active.png create mode 100644 .config/awesome/iceys-theme/titlebar/ontop_focus_inactive.png create mode 100644 .config/awesome/iceys-theme/titlebar/ontop_normal_active.png create mode 100644 .config/awesome/iceys-theme/titlebar/ontop_normal_inactive.png create mode 100644 .config/awesome/iceys-theme/titlebar/sticky_focus_active.png create mode 100644 .config/awesome/iceys-theme/titlebar/sticky_focus_inactive.png create mode 100644 .config/awesome/iceys-theme/titlebar/sticky_normal_active.png create mode 100644 .config/awesome/iceys-theme/titlebar/sticky_normal_inactive.png create mode 100644 .config/awesome/rc.bak2.lua create mode 100644 .config/awesome/rc.lua create mode 100755 .config/dwm/autostart.sh create mode 100755 .config/dwm/newsboat-fetch.sh create mode 100644 .config/gtk-3.0/settings.ini create mode 100644 .config/lf/lfrc create mode 100644 .config/nvim/.luarc.json create mode 100644 .config/nvim/after/plugin/harpoon.lua create mode 100644 .config/nvim/after/plugin/lsp.lua create mode 100644 .config/nvim/after/plugin/telescope.lua create mode 100644 .config/nvim/after/plugin/undotree.lua create mode 100644 .config/nvim/custom-lsp/.luarc.json create mode 100644 .config/nvim/init.lua create mode 100755 .config/nvim/lua/yourmom/init.lua create mode 100755 .config/nvim/lua/yourmom/packer.lua create mode 100755 .config/nvim/lua/yourmom/remap.lua create mode 100755 .config/nvim/spell/en.utf-8.add create mode 100755 .config/nvim/spell/en.utf-8.add.spl create mode 100644 .config/picom.conf create mode 100644 .config/rofi/config.rasi create mode 100644 .config/screenkey.json create mode 100644 .gitmodules create mode 100644 .gtkrc-2.0 create mode 100755 .profile create mode 100644 .surf/styles/default.css create mode 100755 .urlview create mode 100755 .vimrc create mode 100755 .wezterm.lua create mode 100755 .zshrc create mode 100644 LICENSE create mode 100644 README.md create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/LICENSE create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/Makefile create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/README create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/arg.h create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/config.h create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/config.mk create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/dmenu create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/dmenu.1 create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/dmenu.c create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/dmenu.o create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/dmenu_path create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/dmenu_run create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/drw.c create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/drw.h create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/drw.o create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/stest create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/stest.1 create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/stest.c create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/stest.o create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/util.c create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/util.h create mode 100644 stuff/manual-programs/suckless/dmenu-5.2/util.o create mode 100644 stuff/manual-programs/suckless/dwm-bak/LICENSE create mode 100644 stuff/manual-programs/suckless/dwm-bak/Makefile create mode 100644 stuff/manual-programs/suckless/dwm-bak/README create mode 100644 stuff/manual-programs/suckless/dwm-bak/awesome-glyphs.txt create mode 100644 stuff/manual-programs/suckless/dwm-bak/config.def.h.orig create mode 100644 stuff/manual-programs/suckless/dwm-bak/config.h create mode 100644 stuff/manual-programs/suckless/dwm-bak/config.mk create mode 100644 stuff/manual-programs/suckless/dwm-bak/drw.c create mode 100644 stuff/manual-programs/suckless/dwm-bak/drw.h create mode 100644 stuff/manual-programs/suckless/dwm-bak/drw.o create mode 100644 stuff/manual-programs/suckless/dwm-bak/dwm create mode 100644 stuff/manual-programs/suckless/dwm-bak/dwm-autostart-20161205-bb3bd6f.diff create mode 100644 stuff/manual-programs/suckless/dwm-bak/dwm-fullgaps-6.2.diff create mode 100644 stuff/manual-programs/suckless/dwm-bak/dwm-systray-6.2.diff create mode 100644 stuff/manual-programs/suckless/dwm-bak/dwm.1 create mode 100644 stuff/manual-programs/suckless/dwm-bak/dwm.c create mode 100644 stuff/manual-programs/suckless/dwm-bak/dwm.c.orig create mode 100644 stuff/manual-programs/suckless/dwm-bak/dwm.o create mode 100644 stuff/manual-programs/suckless/dwm-bak/dwm.png create mode 100644 stuff/manual-programs/suckless/dwm-bak/dwmstatus/LICENSE create mode 100644 stuff/manual-programs/suckless/dwm-bak/dwmstatus/Makefile create mode 100644 stuff/manual-programs/suckless/dwm-bak/dwmstatus/config.mk create mode 100644 stuff/manual-programs/suckless/dwm-bak/dwmstatus/dwmstatus-temperature.c create mode 100644 stuff/manual-programs/suckless/dwm-bak/dwmstatus/dwmstatus.c create mode 100644 stuff/manual-programs/suckless/dwm-bak/dwmstatus/new-acpi-battery.c create mode 100644 stuff/manual-programs/suckless/dwm-bak/endx create mode 100644 stuff/manual-programs/suckless/dwm-bak/shiftview.c create mode 100644 stuff/manual-programs/suckless/dwm-bak/transient.c create mode 100644 stuff/manual-programs/suckless/dwm-bak/util.c create mode 100644 stuff/manual-programs/suckless/dwm-bak/util.h create mode 100644 stuff/manual-programs/suckless/dwm-bak/util.o create mode 100644 stuff/manual-programs/suckless/dwm/LICENSE create mode 100644 stuff/manual-programs/suckless/dwm/Makefile create mode 100644 stuff/manual-programs/suckless/dwm/README create mode 100644 stuff/manual-programs/suckless/dwm/awesome-glyphs.txt create mode 100644 stuff/manual-programs/suckless/dwm/config.def.h.orig create mode 100644 stuff/manual-programs/suckless/dwm/config.h create mode 100644 stuff/manual-programs/suckless/dwm/config.mk create mode 100644 stuff/manual-programs/suckless/dwm/drw.c create mode 100644 stuff/manual-programs/suckless/dwm/drw.h create mode 100644 stuff/manual-programs/suckless/dwm/drw.o create mode 100644 stuff/manual-programs/suckless/dwm/dwm create mode 100644 stuff/manual-programs/suckless/dwm/dwm-autostart-20161205-bb3bd6f.diff create mode 100644 stuff/manual-programs/suckless/dwm/dwm-bottomstack-6.1.diff create mode 100644 stuff/manual-programs/suckless/dwm/dwm-fullgaps-6.2.diff create mode 100644 stuff/manual-programs/suckless/dwm/dwm-systray-6.2.diff create mode 100644 stuff/manual-programs/suckless/dwm/dwm.1 create mode 100644 stuff/manual-programs/suckless/dwm/dwm.c create mode 100644 stuff/manual-programs/suckless/dwm/dwm.c.orig create mode 100644 stuff/manual-programs/suckless/dwm/dwm.o create mode 100644 stuff/manual-programs/suckless/dwm/dwm.png create mode 100644 stuff/manual-programs/suckless/dwm/dwmstatus/LICENSE create mode 100644 stuff/manual-programs/suckless/dwm/dwmstatus/Makefile create mode 100644 stuff/manual-programs/suckless/dwm/dwmstatus/config.mk create mode 100644 stuff/manual-programs/suckless/dwm/dwmstatus/dwmstatus-temperature.c create mode 100644 stuff/manual-programs/suckless/dwm/dwmstatus/dwmstatus.c create mode 100644 stuff/manual-programs/suckless/dwm/dwmstatus/new-acpi-battery.c create mode 100644 stuff/manual-programs/suckless/dwm/endx create mode 100644 stuff/manual-programs/suckless/dwm/shiftview.c create mode 100644 stuff/manual-programs/suckless/dwm/transient.c create mode 100644 stuff/manual-programs/suckless/dwm/util.c create mode 100644 stuff/manual-programs/suckless/dwm/util.h create mode 100644 stuff/manual-programs/suckless/dwm/util.o create mode 100644 stuff/manual-programs/suckless/surf/FAQ.md create mode 100644 stuff/manual-programs/suckless/surf/LICENSE create mode 100644 stuff/manual-programs/suckless/surf/Makefile create mode 100644 stuff/manual-programs/suckless/surf/README create mode 100644 stuff/manual-programs/suckless/surf/TODO.md create mode 100644 stuff/manual-programs/suckless/surf/arg.h create mode 100644 stuff/manual-programs/suckless/surf/common.h create mode 100644 stuff/manual-programs/suckless/surf/config.def.h create mode 100644 stuff/manual-programs/suckless/surf/config.def.h.orig create mode 100644 stuff/manual-programs/suckless/surf/config.h create mode 100644 stuff/manual-programs/suckless/surf/config.mk create mode 100644 stuff/manual-programs/suckless/surf/surf create mode 100644 stuff/manual-programs/suckless/surf/surf-modal-20190209-d068a38.diff create mode 100644 stuff/manual-programs/suckless/surf/surf-open.sh create mode 100644 stuff/manual-programs/suckless/surf/surf-uri-aliases-20220930-089272b.diff create mode 100644 stuff/manual-programs/suckless/surf/surf.1 create mode 100644 stuff/manual-programs/suckless/surf/surf.c create mode 100644 stuff/manual-programs/suckless/surf/surf.c.orig create mode 100644 stuff/manual-programs/suckless/surf/surf.o create mode 100644 stuff/manual-programs/suckless/surf/surf.png create mode 100644 stuff/manual-programs/suckless/surf/webext-surf.c create mode 100644 stuff/manual-programs/suckless/surf/webext-surf.o create mode 100644 stuff/manual-programs/suckless/surf/webext-surf.so create mode 100755 stuff/scripts/system/backup/backup.sh create mode 100755 stuff/scripts/system/backup/copy-to-git.sh create mode 100755 stuff/scripts/system/bri.sh create mode 100755 stuff/scripts/system/math.sh create mode 100755 stuff/scripts/system/neoboot.sh create mode 100755 stuff/scripts/system/restart-pipe.sh create mode 100755 stuff/scripts/system/set-pri-java.sh create mode 100644 stuff/scripts/system/stbar/config.txt create mode 100755 stuff/scripts/system/stbar/killbar.sh create mode 100755 stuff/scripts/system/stbar/stbar-awesome.sh create mode 100755 stuff/scripts/system/stbar/stbar.sh create mode 100755 stuff/scripts/system/stbar/weth_str.txt create mode 100755 stuff/scripts/system/url-handler.sh diff --git a/.Xresources b/.Xresources new file mode 100755 index 0000000..1261e1a --- /dev/null +++ b/.Xresources @@ -0,0 +1,82 @@ +! black +*.color0: #263640 +*.color8: #4a697d + +! red +*.color1: #d12f2c +*.color9: #fa3935 + +! green +*.color2: #819400 +*.color10: #a4bd00 + +! yellow +*.color3: #b08500 +*.color11: #d9a400 + +! blue +*.color4: #2587cc +*.color12: #09a2f5 + +! magenta +*.color5: #696ebf +*.color13: #8086e8 + +! cyan +*.color6: #289c93 +*.color14: #00c5ba + +! white +*.color7: #bfbaac +*.color15: #fdf6e3 + +Sxiv.background: #303030 +Sxiv.foreground: #00C0FF +Sxiv.font: Hack-9 + +!tabs +!*.tabbed.tabbar-fg: 2 +!*.tabbed.tabbar-bg: 0 +!*.tabbed.tab-fg: 3 +!*.tabbed.tab-bg: 1 + +!*.highlightColor: #bdbdbd +!*.highlightTextColor: #000000 + +!start size +!URxvt.geometry: 120x30 +URxvt.scrollBar: false + + +URxvt.transparent: true +URxvt.depth: 10 +URxvt.shading: 110 +!URxvt.font: xft:cousine:size=12 +URxvt.font: xft:Inconsolata-Regular:size=15 +URxvt.foreground: #e6e6e6 +URxvt.background: #000000 + +URxvt.tintColor: [100]#111111 +URxvt.cursorColor: #fabd2f + +URxvt.inputMethod: ibus +URxvt.preeditType: OverTheSpot + +/* +URxvt.keysym.Shift-Up: command:\033]720;1\007 +URxvt.keysym.Shift-Down: command:\033]721;1\007 +URxvt.keysym.Control-Up: \033[1;5A +URxvt.keysym.Control-Down: \033[1;5B +URxvt.keysym.Control-Right: \033[1;5C +URxvt.keysym.Control-Left: \033[1;5D +*/ +URxvt.iso14755: false +!URxvt.perl-ext-common: default,resize-font +!URxvt.perl-ext-common: default,resize-font,-tabbed +URxvt.perl-ext-common: default + +URxvt.keysym.Shift-Control-V: eval:paste_clipboard +URxvt.keysym.Shift-Control-C: eval:selection_to_clipboard +!URxvt.keysym.C-j: resize-font:smaller +!URxvt.keysym.C-k: resize-font:bigger +!URxvt.keysym.C-equal: resize-font:reset diff --git a/.bash_profile b/.bash_profile new file mode 100644 index 0000000..f340060 --- /dev/null +++ b/.bash_profile @@ -0,0 +1,18 @@ +# +# ~/.bash_profile +# + +[[ -f ~/.bashrc ]] && . ~/.bashrc + +#!/bin/bash +if test -z "${XDG_RUNTIME_DIR}"; then + export XDG_RUNTIME_DIR=/tmp/${UID}-runtime-dir + if ! test -d "${XDG_RUNTIME_DIR}"; then + mkdir "${XDG_RUNTIME_DIR}" + chmod 0700 "${XDG_RUNTIME_DIR}" + fi +fi + + +#export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):0 +export DWM_NOTIF_FILE="/home/iceyrazor/stuff/scripts/c/SDL/notif/notif.txt" diff --git a/.bashrc b/.bashrc new file mode 100755 index 0000000..a92d2ed --- /dev/null +++ b/.bashrc @@ -0,0 +1,10 @@ +# +# ~/.bashrc +# + +# If not running interactively, don't do anything +[[ $- != *i* ]] && return +PS1='\[\e[37;1m\][\[\e[31;1m\]B\[\e[35;1m\]\u\[\e[33m\]@\[\e[35;1m\]\h \[\e[36;1m\]\W\[\e[37;1m\]]\[\e[0;1m\]∮ ' + +source ~/stuff/scripts/system/neoboot.sh +source ~/.profile diff --git a/.config/awesome/iceys-theme/layouts/cornerne.png b/.config/awesome/iceys-theme/layouts/cornerne.png new file mode 100644 index 0000000000000000000000000000000000000000..c85bd56a3ccc2cd058c1ebdaeb9d7a8fb683b644 GIT binary patch literal 272 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e&H|6fVxatW5N34Jm|X!BWH0gb zb!ETLD$CC=?c6u53@F4O;1l8sq;qp~&CJY{l$4%5d)D%1Z97nixg^Lhm|^yBr!{+K z1G$Vz-tI0e{TVj{ft(6Y7sn8f<8P;2D!DgUFQ zvtokxOW{S2gWicwl|Halckd!E=67*gS`Folk<++O?22{RB0Pi7@^9K5=Q~SScPO$I zW*k+>%syR_E9zh+d2j;LhJU^DH%s06&tS8w+3n&B{iwaM>cVFjj=J9!-3W98gQu&X J%Q~loCIF4@UM2tl literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/layouts/cornernew.png b/.config/awesome/iceys-theme/layouts/cornernew.png new file mode 100644 index 0000000000000000000000000000000000000000..c3fd98618746b81cb7940ac9088bd53cc4f18967 GIT binary patch literal 272 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e&H|6fVxatW5N34Jm|X!BWH0gb zb!ETLD$CEW^7X}TZ=eu=fKP}kkY2H3g_4re#ful8J$p8xPa9+=Q%R6tFvEej-}yU$ zJjNt%cNeBK?wS-Jr_$5KF~p?6*E#@GHO2;#GlO*PXD5)2AA80v*BN>FVdQ I&MBb@04)MuU;qFB literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/layouts/cornernw.png b/.config/awesome/iceys-theme/layouts/cornernw.png new file mode 100644 index 0000000000000000000000000000000000000000..dfe78b3da94de0befd857e47a253647df611d6ea GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e&H|6fVxatW5N34Jm|X!BWH0gb zb!ETLD$CE$9Po%w0Vu>D;1l8sq;qp~&CJY{l$4%5d)D%1Z97nixg^Lhm|^yBr!{+K z1G$Vz-tI0e{TVj{ft-9#7sn8fbnQLB)w7Xd#)}nA z2NyIXq$s+Ym$7;z91syGd6F?p#)<32Y_*NzNi5xtkG%YAxHj%+tzmWIn679zQA9)e yPur0rV&V}qlsy^0H8^=qzR^4@q2#h41H+^LjFlfYZ!rK`&EV>}Vp2D^ r&Y6iz7^)o5Too+pxq3fu6{1-oD!M<`?yVv literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/layouts/cornerse.png b/.config/awesome/iceys-theme/layouts/cornerse.png new file mode 100644 index 0000000000000000000000000000000000000000..023ae79ad454e06284a5c7aa0cc429d3baf16c29 GIT binary patch literal 264 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e&H|6fVxatW5N34Jm|X!BWH0gb zb!ETLD$CDr#s9ob11Q8F;1l8sq;qm|l$4ar%*>uWdsZo0kN^~7DhcunX1JcG(&Z22 zF(!GtyRh_U+zbSA3O!vMLp+WrCrF4mcyMy?EHq&g=IC+oN!92*$il=S?Y7w1eI8R2 zW2^Csi9Cn-G{O~HHuQFsG;#%Ol}ywMIQB>^#9s;wQHC1ea37z{MmJ~$Pjeh+9lgQu&X%Q~loCIDN5N(cY| literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/layouts/cornersew.png b/.config/awesome/iceys-theme/layouts/cornersew.png new file mode 100644 index 0000000000000000000000000000000000000000..f7cfa1c0db222304f9d880c023601c576fd5e040 GIT binary patch literal 264 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e&H|6fVxatW5N34Jm|X!BWH0gb zb!ETLD$CDrTxM<80~F#9@Ck7R(koW1P*PI5c=6)1XU`_|X@ksUDhcunW;pQnJAVg| z$C%{p?!uJDU6TUj6neTihIkxLPLL3BIKs-ov(SW1n8U}xCtaiWAPW_56RBi3pEFojSz;MPdY~mqR<8MIA89ZJ6T-G@yGywpICQY0G literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/layouts/cornersw.png b/.config/awesome/iceys-theme/layouts/cornersw.png new file mode 100644 index 0000000000000000000000000000000000000000..c1453c9fd005d78c90ca4021c97ff7a6be40bfcc GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e&H|6fVxatW5N34Jm|X!BWH0gb zb!ETLD$6gx!IgE>3@F4O;1l8sq;qm|l$4ar%*>uWdsZo0kN^~7DhcunX1JcG(&Z22 zF(!GtyRh_U+zbSA3OrpLLp+YZof62!pvd8}+gUvz|H5DX?E$(y78m@lZ2G!SMNXn` z#wGO=wPwJ~P-p(1|6&#G~0 yWvlHWgEfhFxWnGPd*aVpcSJ#_j!p61Tbp%GYjv0{uI~Wa&EVC;4o;^Fa;`B725K~EzUogWn`(It9 zKpta~x4R2d8h1?!kW=XC;uzx5`F6@dP6kCDmbVAPaukmI%NDX}<&FGMykf;?E~5z# z+FCZS8rFB{FXdXfca{EDuAR=OX0!YYRQRx-t@M^E$9@=QD@S+`Ag zYY6j?(BU~Ob<8&L={-L=tq;mFVdQ&MBb@01#$Z AEC2ui literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/layouts/dwindle.png b/.config/awesome/iceys-theme/layouts/dwindle.png new file mode 100644 index 0000000000000000000000000000000000000000..9902d22d9fe71e7fcb27ebb4dc6060e5d1bf6b1e GIT binary patch literal 320 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e=3*z$5DpHG+YkL80J)q69+AaB z<<~)&(Me-=1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWD?t0G|+7 zAgu@n%F4=0xPhwB%yOVoo{}KHUeVH?;Y4|>V5y~}6KPNpN c8ax1cTu7JkOv%?(R3)DDQp8<e zr8>M=riXfO(0aibc>LhKqv39jF9KOzSf+@t`_dqo$-IIgz3RXRwQF8)RVFd%r?5_5 g_~)d@LxTrEj|=HCo+mdKI;Vst02Qcz*8l(j literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/layouts/fairh.png b/.config/awesome/iceys-theme/layouts/fairh.png new file mode 100644 index 0000000000000000000000000000000000000000..d41deead1ee2490ce0ada3a48c16a9a898535222 GIT binary patch literal 245 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e=3*z$5DpHG+YkL80J)q69+AaB z<<~)&(Me-=1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWD>W0G|+7 zAg!#dtb_r6|GT*ZD92tBE-?C@snutH7kHZHl8kyAs)w*6C^|qtdZeq+OWAn zLFSO=!E;PaMH&arNrf7$O3=_!nDHi5QO5nv8b>C#;_oY(0$C3ml`}K&>)WzVFDqRJ PG>5^{)z4*}Q$iB}b|yz_ literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/layouts/fairhw.png b/.config/awesome/iceys-theme/layouts/fairhw.png new file mode 100644 index 0000000000000000000000000000000000000000..bb50e3ae13ecba910f0777618649b856f6408328 GIT binary patch literal 245 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e=3*z$5DpHG+YkL80J)q69+AaB z<<~)&(Me-=1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWD>W0G|+7 zApIN$o*{vQ7k^g)<=9Jt{DK)gy}TbieiCiIW(82l#?!?y#N&8!f`rI{H8MO+8#Xs6 z$Q;rW0G|+7 zAg!#dtb_r6|GT*ZD92tBE-?C@snutH7kHZww^AIAs)w*6C^|qtdU`CGT7lD z(5DjAbda^FD5c?`Y^Z}jD~qzXsOJ&EW^0cF8M9=3Coj${3OSfD>j*PL%Qsv0xNA?< Qfd(;ny85}Sb4q9e0A;#IW&i*H literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/layouts/fairvw.png b/.config/awesome/iceys-theme/layouts/fairvw.png new file mode 100644 index 0000000000000000000000000000000000000000..4f4ed52219e33c9189a536b712b3cc82f277ff4a GIT binary patch literal 246 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e=3*z$5DpHG+YkL80J)q69+AaB z<<~)&(Me-=1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWD>W0G|+7 zApIN$o*{vQ7k^g)<=9Jt{DK)gy}TbieiCiIW(82l*3-o?#N&8!f`rI{H8PA%20I)C z`c#6N4ze~Cr8FFr4R!EmWl{DP^*kcjZ0&I%W0s8X#j+S3j3^P6`0G|+7 zAgv4rO4z{SwStR5c9aD91vAKcdU`R)Q0)K! literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/layouts/floatingw.png b/.config/awesome/iceys-theme/layouts/floatingw.png new file mode 100644 index 0000000000000000000000000000000000000000..481589427960286e42e6c5c4e764e1222dccf10d GIT binary patch literal 282 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e=3*z$5DpHG+YkL80J)q69+AaB z<<~)&(Me-=1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWD>`0G|+7 zApP{|)8{bo3>BQ=6(|JRQ4-`A%pmLO<-P6E<0mbTVp4&Ek)AG&As)w*6C^|qB&&%9 z^ekB*G`lI&gDWkGbupKlXph!{UZx7Zql*)y6j_a5E@cR3WC~B{^K}%O#1zwz#M;v$ w(vhU0AdtG4t8Ge?*Pl@7Yg=ZTSZL)joT}LD)L)->8fXcFr>mdKI;Vst0H7CS?*IS* literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/layouts/fullscreen.png b/.config/awesome/iceys-theme/layouts/fullscreen.png new file mode 100644 index 0000000000000000000000000000000000000000..d02f6fc339a93c92f0b238c89d1889d3da811381 GIT binary patch literal 866 zcmV-o1D*VdP)lCcZQz;03CZsP%%N zFX}ho(MS2V;Ipwe=t2SiW42_n*)BVCrtNG!Cpjs-@=h`8S5d z%Md=Q#!;|cmtq6+mxXXC-tud^uJdYRzA^w$-t+D>*XoMjA6K`yDRNfws0E7+}LSGu)9``0l z;J0V+rtRX5B}n+C$XEzLh<`DZ6q!LuQYi4LB@leY8%vV%rpbBs-p1W0v_uR6a>!|N zry;UK##IyAXydgIdd?^SPD17fJ;A*V+r+zidK3VTLWbC=AhawkTwNCL-*u~ zK?r|z#k+c%6aY<;rjDxjSO^;AxNil%>2*A}=N*O={mgyGrjM@##Ux^OQ}&y@BE$gH s0Q~odrs@+4VP7P5^T9|qHa6M*0ydFz%Ff(hL;wH)07*qoM6N<$f+5&_C;$Ke literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/layouts/fullscreenw.png b/.config/awesome/iceys-theme/layouts/fullscreenw.png new file mode 100644 index 0000000000000000000000000000000000000000..5c35bfa8afe6c4f091f3895d92c50f845df52483 GIT binary patch literal 865 zcmV-n1D^beP)DEINg2jB%EarEGlDCI7^0NIKDE~nlw6Yw>-q|E}IwOrD#hdl~f3bJRyW_bzF)=YQ%_^13 zn{v5agdfb97ocr@BminSgW?D7L;-Lx%Ps)o0)Wly$Lsa_*?c~KahMm2#l>2!c9$IY z+$Q?yGXm~YAA|m=@33=IYCA(F92Hli(KyEj&}=r(j}X5;Veye6v|6nTYydRB4r@!7q6%bM ziB0J3K(Vs{U?8~^^3c>vKz6qa{}dD>B~CU5!OIC2uS3`fi1P{?07lZQzT+F}gh|Wu z_i;OX)ni5ae9guza9un0IicbMAz&7`!3N+s&drpF{|^EFO(jCN*Z?q)+{V51B_-l@ z2;Xrv+_5nT{($eL@Y$ar{FDU|0U!VbfB+Bx0zd!=00AHX1b_e#00O`WfR|#yo{dG( zxA@#np?Fs<08*GlI2*N+{);34=?eP>qa3T7+)$MVAfdsx= zf_IWG-dce~P>DRp9nPEjzSaW}p5D0C0^<2aR9h+t24(4p$lIzs9OEa0kCaYCww2?vM9cdB~x)0G|+7 zAg!jRrlO*v3L8SBlE>)0G|+7 zApQ99<0ns^Jbn7~ISf3*2JDrd=>S#pmIV0)Gf2zGdU|2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4b=pctzcxp`j&fO&(QQ6C>GkF+rq|wF-V;qT%Xi;A z$@3&v@g)BwpSCrIQb4eiVFT|2<^wSivl%mXGn`@ZtGl>NkD>UaFC!DPM{YNN!_42^ zcAYPb%o=ib#;5J;V@(LSP#$i=AZTmx<-RcIfiwEYW*kuz_nz@HQ0l-9iOZinJcJqi zgBap$)#tlQcrnZnxOiKO_kfGBBWnNy7&Rm?9%HzdJ?Fyo_qv-*7-rwzzRDx4hN0#) z=TZiNi=UPD@-iOiQ@$&5z@UCLH|v4Er#rG5-t@n3W-M@wkW`32%q@9f+I7CuY%fG> z?pIl{9c{FIQwqT6hGjm?|P5AJ5mZE_ElZT^0G>fMaK zgKa8K&o3@J?C=Q%(yQ$6qayO?wu2_WHwohM8h6A`XlY)WrHDX0xeW!iHnJ zpRSvtI^n0^zE$bPrFN5E?e^Pus(o^4e$z_l|0}-)F9^O+uHKbAVdnXm?24q%3`$nI ztL`0}#4(rQ#zmh1#zRaU|CX=Z7SN(;od2?aA~48*{$RCRx%I-Xea|lg2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4jwZ_m&7OIeW7A=9_Z| z?y;Kvo_O{gkEcKe5G-k$xt(zjv%v9VlVmmVXx4b(9RRfI-|p5hWY-EmNS1|NFDHTv2xuUD9G9Q z;v^?STAk+RA0|u<8@c@t$Q;N%YIxlzfKkK&j1ELKNH%O|6aNyqt;>YdKyad;>`5=l zhE0E2f*H=Q{&J12L4l)b(OgwwhQ}qL>D&%Y1u^CacKP+0GPnw8F)yjEFk@Eno$9=p z;f&3h9rvsnSQ77ZFc`-_kI7ecD9Yc>u&XqaPgjqFHcVj6un2)oY18 z|L@-X`b;9nQ>o-#t`^UONBg@Mu5>+mAvO5vhb<3_esDXi;T2>JV1S@(M!SC&QTzt0 ze%&pSmG?E>%KC__Ti)U;-;FCFcMJGy)#IC7M4q0F|Gs>4?|h~+cTQ&{f32}(JKy!~ zL(Dm5zseVH?;Y4|YH4ETUc-UaS>tnUB<;@-y)(9=rh^uTT#p6zJ jsU5!5EUpyKW5K}Csin)9_P(eI=nMu=S3j3^P6(R3)DDQp8<g zO?Ko2F&7FIRtmq^D<|;WLXNe9=@j>ydK<0@v1S2W3J)9XcYUlDw!GP+!WyAv8gZ5F oq~0iD6%>FVdQ&MBb@07`m(0ssI2 literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/layouts/tile.png b/.config/awesome/iceys-theme/layouts/tile.png new file mode 100644 index 0000000000000000000000000000000000000000..3ede21e8cf98ce00b16ced05213f7436c8dc6664 GIT binary patch literal 265 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e=3*z$5DpHG+YkL80J)q69+AaB z<<~)&(Me-=1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWD>W0G|+7 zAg!#dtb_r6|GT*ZD92tBE-?C@snutH7kHZ0iG_7As)w*6C^|qtdZeq+OWAn zLFSO=!E;PaMH&arNrf61aB;Xz(`tFxaVE*Zm`{4aY9^V?Ni6w&%i1rRSk6*&7hRyG k5V11RyHg{x=l~mdKI;Vst0FISWYybcN literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/layouts/tilebottom.png b/.config/awesome/iceys-theme/layouts/tilebottom.png new file mode 100644 index 0000000000000000000000000000000000000000..6f8c2570ae64d88453f888fadb1e6e20b4b7e531 GIT binary patch literal 264 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e=3*z$5DpHG+YkL80J)q69+AaB z<<~)&(Me-=1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWD>W0G|+7 zAg!#dtb_r6|GT*ZD92tBE-?C@snutH7kHZ{+=$5As)w*6C^|qtdUXYVAAF| zzIFl2ngufa5}^+9tSrjjqT88{ADpNlm}$ge&HeDK&>Nj44TsK2g*y0yW#|3du+i=E glNC)DO*%OlY~*!5=bHM@0UFKV>FVdQ&MBb@0B_1oUH||9 literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/layouts/tilebottomw.png b/.config/awesome/iceys-theme/layouts/tilebottomw.png new file mode 100644 index 0000000000000000000000000000000000000000..a1de7b29fc3476f41d29ed09b6c87a6880aeb785 GIT binary patch literal 264 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e=3*z$5DpHG+YkL80J)q69+AaB z<<~)&(Me-=1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWD>W0G|+7 zApIN$o*{vQ7k^g)<=9Jt{DK)gy}TbieiCiIW(82l-_yl0#N&8!f`rI{H8ScPOxhgB z*DhdLvp|MlBGe(Cl||WGbUV}WgA)}5GmSW`xgVYtdZV+X;m|p$PzQgo?7V*)Ho9GY gvZCptNhc?Rjl9n1TvPu!K%*HvUHx3vIVCg!0M2k+^#A|> literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/layouts/tileleft.png b/.config/awesome/iceys-theme/layouts/tileleft.png new file mode 100644 index 0000000000000000000000000000000000000000..31d6870477a706d765b66ebb3ac2f76ba2bbd0ee GIT binary patch literal 266 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e=3*z$5DpHG+YkL80J)q69+AaB z<<~)&(Me-=1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWD>W0G|+7 zAg!#dtb_r6|GT*ZD92tBE-?C@snutH7kHZfu1goAs)w*6C^|qtdZeq+OWAn zLFSO=!E;PaMH&arNrgK2v))+5;o7Lx^0woQQ(yz{g=ofYQ#@vwyI($>F-yjG@?tIz l&&e87rM8)LCh)Q`Fl5cw`Mk`lcR$c@22WQ%mvv4FO#m>2QJMe% literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/layouts/tileleftw.png b/.config/awesome/iceys-theme/layouts/tileleftw.png new file mode 100644 index 0000000000000000000000000000000000000000..cf14c25e6dfcea21b1ce34e1a8e26da6d865f895 GIT binary patch literal 266 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e=3*z$5DpHG+YkL80J)q69+AaB z<<~)&(Me-=1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWD>W0G|+7 zApIN$o*{vQ7k^g)<=9Jt{DK)gy}TbieiCiIW(80v(9^{+#N&8!f`rI{H8MO+8#Xs6 z$Q;r)HajO1YR}`BGVKD#z literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/layouts/tiletop.png b/.config/awesome/iceys-theme/layouts/tiletop.png new file mode 100644 index 0000000000000000000000000000000000000000..98cade20c8ad66f318a3c9ce484f54c7f5cc0fc4 GIT binary patch literal 260 zcmeAS@N?(olHy`uVBq!ia0vp^79h;R3?!pgsObVJ=3*z$5DpHG+YkL80J)q69+AaB z<<~)&(Me-=1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWD>W0G|+7 zAg!#dtb_r6|GT*ZD92tBE-?C@snutH7kHZ-kvUwAr_~T4Yb*t71-Ex))a6o zZef&OEyE?TVWXR>=A<@e#^D fu=>%o5*CIkC!Nn+FN#Hg#xi)i`njxgN@xNAmIg|^ literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/layouts/tiletopw.png b/.config/awesome/iceys-theme/layouts/tiletopw.png new file mode 100644 index 0000000000000000000000000000000000000000..d1d0872b8a6008c2686a6c455a412e7ae428166e GIT binary patch literal 265 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e=3*z$5DpHG+YkL80J)q69+AaB z<<~)&(Me-=1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWD>W0G|+7 zApIN$o*{vQ7k^g)<=9Jt{DK)gy}TbieiCiIW(80vz|+Ms#N&8!f`rI{H8MO+8#Xs6 z$Q;rW0G|+7 zApIN$o*{vQ7k^g)<=9Jt{DK)gy}TbieiCiIW(80vz|+Ms#N&8!f`rI{H8MO+8#Xs6 z$Q;rP000>X1^@s6#OZ}&00004b3#c}2nYxW zd2z8Hj+`L9UQg2LG>t}MEh2;Ea(U|nQA(kdBAd<9YPAv(`2en+Ap7$9 zJe^KwE+TKhr4wXdu~;OEA~PC|UVw8a$i8y9{L}CE<2a6=fKw-kQVQSqsaC6BA~H^r zQjEnx?oJHr&dIz4a@dl*-CY>| zgW!U_%O?XxI14-?iy0WWg+Z8+Vb&Z8pdfpRr>`sf4K5~rW#b#FTbqDFk|nMYCC>S| zxv6<249-QVi6yBi3gww484B*6z5(HleBwYwVxBIJAr_~TfA}*P^a!vnP7vu~;$dKz X$MK&rzAi=usDi=M)z4*}Q$iB}5zjAs literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/taglist/squarew.png b/.config/awesome/iceys-theme/taglist/squarew.png new file mode 100644 index 0000000000000000000000000000000000000000..913f2ca6ba168e824644509d6fed72b31c677d49 GIT binary patch literal 193 zcmeAS@N?(olHy`uVBq!ia0vp^96+qV!3HGtKUiJ>QjEnx?oJHr&dIz4a@dl*-CY>| zgW!U_%O?XxI14-?iy0WWg+Z8+Vb&Z8pdfpRr>`sf4K5~rW$n|Rx>tZgk|nMYCC>S| zxv6<249-QVi6yBi3gww484B*6z5(HleBwYwGM+AuAr_~TfA}*PG;qo!WN03EeKyd5 d%Z(A}pyPS@6O*PM?E$J|@O1TaS?83{1OQ#WGiU$+ literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/theme.lua b/.config/awesome/iceys-theme/theme.lua new file mode 100644 index 0000000..1bbefc3 --- /dev/null +++ b/.config/awesome/iceys-theme/theme.lua @@ -0,0 +1,147 @@ +--------------------------- +-- Default awesome theme -- +--------------------------- + +local theme_assets = require("beautiful.theme_assets") +local xresources = require("beautiful.xresources") +local dpi = xresources.apply_dpi + +--local gfs = require("gears.filesystem") +--local themes_path = gfs.get_themes_dir() +local themes_path=debug.getinfo(1,"S").source:gsub("theme.lua",""):gsub("@","") + +local theme = {} + +theme.font = "inconsolata regular 10" + +--#8558e6 + +theme.bg_normal = "#432990" +theme.bg_focus = "#453996" +theme.bg_urgent = "#ff0000" +theme.bg_minimize = "#111111" +theme.bg_systray = theme.bg_normal +theme.tasklist_bg_normal = "#222222" + +--[[ +theme.bg_normal = "#432990" +theme.bg_focus = "#453996" +theme.bg_urgent = "#ff0000" +theme.bg_minimize = "#444444" +theme.bg_systray = theme.bg_normal +--]] + +theme.fg_normal = "#aaaaaa" +theme.fg_focus = "#eeeeee" +theme.fg_urgent = "#eeeeee" +theme.fg_minimize = "#eeeeee" + +theme.useless_gap = dpi(2) +theme.border_width = dpi(2) +theme.border_normal = "#222222" +theme.border_focus = "#8558e6" +theme.border_marked = "#91231c" +theme.gap_single_client = true + +-- There are other variable sets +-- overriding the default one when +-- defined, the sets are: +-- taglist_[bg|fg]_[focus|urgent|occupied|empty|volatile] +-- tasklist_[bg|fg]_[focus|urgent] +-- titlebar_[bg|fg]_[normal|focus] +-- tooltip_[font|opacity|fg_color|bg_color|border_width|border_color] +-- mouse_finder_[color|timeout|animate_timeout|radius|factor] +-- prompt_[fg|bg|fg_cursor|bg_cursor|font] +-- hotkeys_[bg|fg|border_width|border_color|shape|opacity|modifiers_fg|label_bg|label_fg|group_margin|font|description_font] +-- Example: +--theme.taglist_bg_focus = "#ff0000" + +theme.taglist_bg_empty="#222222" +theme.taglist_bg_occupied=theme.taglist_bg_empty + +-- Generate taglist squares: +local taglist_square_size = dpi(4) +theme.taglist_squares_sel = theme_assets.taglist_squares_sel( + taglist_square_size, theme.fg_normal +) +theme.taglist_squares_unsel = theme_assets.taglist_squares_unsel( + taglist_square_size, theme.fg_normal +) + +-- Variables set for theming notifications: +-- notification_font +-- notification_[bg|fg] +-- notification_[width|height|margin] +-- notification_[border_color|border_width|shape|opacity] + +-- Variables set for theming the menu: +-- menu_[bg|fg]_[normal|focus] +-- menu_[border_color|border_width] +theme.menu_submenu_icon = themes_path.."submenu.png" +theme.menu_height = dpi(15) +theme.menu_width = dpi(100) + +-- You can add as many variables as +-- you wish and access them by using +-- beautiful.variable in your rc.lua +--theme.bg_widget = "#cc0000" + +-- Define the image to load +theme.titlebar_close_button_normal = themes_path.."titlebar/close_normal.png" +theme.titlebar_close_button_focus = themes_path.."titlebar/close_focus.png" + +theme.titlebar_minimize_button_normal = themes_path.."titlebar/minimize_normal.png" +theme.titlebar_minimize_button_focus = themes_path.."titlebar/minimize_focus.png" + +theme.titlebar_ontop_button_normal_inactive = themes_path.."titlebar/ontop_normal_inactive.png" +theme.titlebar_ontop_button_focus_inactive = themes_path.."titlebar/ontop_focus_inactive.png" +theme.titlebar_ontop_button_normal_active = themes_path.."titlebar/ontop_normal_active.png" +theme.titlebar_ontop_button_focus_active = themes_path.."titlebar/ontop_focus_active.png" + +theme.titlebar_sticky_button_normal_inactive = themes_path.."titlebar/sticky_normal_inactive.png" +theme.titlebar_sticky_button_focus_inactive = themes_path.."titlebar/sticky_focus_inactive.png" +theme.titlebar_sticky_button_normal_active = themes_path.."titlebar/sticky_normal_active.png" +theme.titlebar_sticky_button_focus_active = themes_path.."titlebar/sticky_focus_active.png" + +theme.titlebar_floating_button_normal_inactive = themes_path.."titlebar/floating_normal_inactive.png" +theme.titlebar_floating_button_focus_inactive = themes_path.."titlebar/floating_focus_inactive.png" +theme.titlebar_floating_button_normal_active = themes_path.."titlebar/floating_normal_active.png" +theme.titlebar_floating_button_focus_active = themes_path.."titlebar/floating_focus_active.png" + +theme.titlebar_maximized_button_normal_inactive = themes_path.."titlebar/maximized_normal_inactive.png" +theme.titlebar_maximized_button_focus_inactive = themes_path.."titlebar/maximized_focus_inactive.png" +theme.titlebar_maximized_button_normal_active = themes_path.."titlebar/maximized_normal_active.png" +theme.titlebar_maximized_button_focus_active = themes_path.."titlebar/maximized_focus_active.png" + +theme.wallpaper = themes_path.."background.png" + +-- You can use your own layout icons like this: +theme.layout_fairh = themes_path.."layouts/fairhw.png" +theme.layout_fairv = themes_path.."layouts/fairvw.png" +theme.layout_floating = themes_path.."layouts/floatingw.png" +theme.layout_magnifier = themes_path.."layouts/magnifierw.png" +theme.layout_max = themes_path.."layouts/maxw.png" +theme.layout_fullscreen = themes_path.."layouts/fullscreenw.png" +theme.layout_tilebottom = themes_path.."layouts/tilebottomw.png" +theme.layout_tileleft = themes_path.."layouts/tileleftw.png" +theme.layout_tile = themes_path.."layouts/tilew.png" +theme.layout_tiletop = themes_path.."layouts/tiletopw.png" +theme.layout_spiral = themes_path.."layouts/spiralw.png" +theme.layout_dwindle = themes_path.."layouts/dwindlew.png" +theme.layout_cornernw = themes_path.."layouts/cornernww.png" +theme.layout_cornerne = themes_path.."layouts/cornernew.png" +theme.layout_cornersw = themes_path.."layouts/cornersww.png" +theme.layout_cornerse = themes_path.."layouts/cornersew.png" + +-- Generate Awesome icon: +theme.awesome_icon = theme_assets.awesome_icon( + theme.menu_height, theme.bg_focus, theme.fg_focus +) + +-- Define the icon theme for application icons. If not set then the icons +-- from /usr/share/icons and /usr/share/icons/hicolor will be used. +theme.icon_theme = nil + +return theme + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/.config/awesome/iceys-theme/titlebar/close_focus.png b/.config/awesome/iceys-theme/titlebar/close_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..01ef82565db041f356c02173b69cc60d4275ebac GIT binary patch literal 966 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!n2Vh}LpV4%Za?&Y0OWEOctjQh zm0t&8MkkHg6+l7B64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq!<_&xdVJc zT!D&Tym;~I)vMR9U*Erf|KY=jj~_pN^5n_$=g)!SFJHcdNCDXpaiG-Gr%#{308kka zU==|Y1S$t|(L^9-0JXymL!q%MMp1#p!DR@N62i=tE3PgD21i6mkY6wZHxI9XppdYr zn7D+buAaVup^>qPshNL3U{FYCQgTXKdPaFeQ*%peTYJaEt=o6(+_ih}zWoO-U%7hy z#+|$O9z1;V^x5+luU@}-`|kaRkDoq&`TFhqkKcd(%3u2Y02uTqJzX3_A`ZWumK)CK zDAKTo?C#?C@7}z4eJ{WIoz3|>H+LIbPkPcO zT_)&}qW5a;_xEL6XWZuNx^(aFB?+E|;X!eXH9vRoYuItE?)%BEu=r(R){Pf|e-z%; z@J?}TnJ=+R=YD_p)<)BgPiq|Km`jU2>}6a2N9eOmXnm#WDM<_N`sBH57|+V*{qS&< zvs&XgPvV#1wD1R0bR3v-I##Xt$H||6<($>5Y2Ca!@`1}9^Kl&1oxnD!J$p{%<%5lh z#|}&6zumikS^1$FIfcfe=LgKsRGwInlKJmp)Y?M_4y&HJC%ug?ws~T^l-GWy;|Y%z zwtk9F$T#?G;LR)G9UvRc4KRow-fb&cb*-4*ICvIvpQT&i8az9j~`PpLr(2)OI5~f;Q zIrk#@Z|Bq0)<3!~vlxG|R_es<6ne-rr9xhAmE(l?GYYfo-alfSxig_dDy8IT;P!vV zyCpT^jy%Y`B!2dI>TFMGa z5^?zLwA^q;N0El@9DzBVFM97y2yvM>Ws;6}Zs50n|Ko+!Wp@|9fA{9a>wEdt?`+QB zxw+fedeW0N=`ul&6unn#zrQcrI^#B9*QI-ZFG=t$3=fK9togZvU&D@Tb>B~Rg~cxm zvu?Zy{G;%$hIfi%%Y2DlI`{j#w>Fw~d|Kl;$6Q+MVK3YAKSG~nLhCC{Pf1#E*C)?i z!+2Ic?}vw@oYfk~c@n=2r-eV5qT|4v)3IvBKTiJqE9b0cP3z{>kq=z-YuyScjQ6lCGoSzQsT!(5~#Z=DoQvI1HYyelF{r5}E*-qWlX0 literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/titlebar/floating_focus_active.png b/.config/awesome/iceys-theme/titlebar/floating_focus_active.png new file mode 100644 index 0000000000000000000000000000000000000000..82dcc7ca6d97a2a90afcde2bd3be3e4826e0d5f3 GIT binary patch literal 386 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!n2Vh}LpV4%Za?&Y0OWEOctjQh zm0t&8MkkHg6+l7B64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1UT1AIbU zf%O0X|6ja#@$A{N=U@O~Jbn5U!Ud9W5g>y|P~P?KEYN6~k|4ie24+PQQ!^V+-^{G+ zh09lN+qwI|xm$Pdzxwp!*WWnt!uLRRrJgR1ArXh)UN`4!aNuzXEIL=%xbwedX66Rn zT;@xE>f#=say)Qj@h!*PZq@@E*sT~hytyc>;LyO(*w4t#u;Y|)!)MkHjtSctdKpAM zuQGFCN;oHd!=~}eCWezgu9X~Mdh*MWL*NJVgq79m%!$=nzbEkvRhKbuc(fzzzhWgQ P3>Z9J{an^LB{Ts5w(z^i literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/titlebar/floating_focus_inactive.png b/.config/awesome/iceys-theme/titlebar/floating_focus_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..c19ba8005593d7583ec3dc84785ef4ad0763d197 GIT binary patch literal 237 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e=3*z$5DpHG+YkL80J)q69+AaB z<<~)&(Me-=1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWD>u0G|+7 zApIN$o`HeG-IvZlQPz?mzhH*Utn5!B`!7xc3fOqMIEHu}Pfn0vEl3dJV)o0B(I{x` zZe38gKtY7@g2iGkH_-`;8xkf3H+EYtDs(HpwxTJJ^{`DkuK@!?wUIr~`8_{-faWlG My85}Sb4q9e0L<`Cxc~qF literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/titlebar/floating_normal_active.png b/.config/awesome/iceys-theme/titlebar/floating_normal_active.png new file mode 100644 index 0000000000000000000000000000000000000000..62342d19e7a9fad2384d3ebb68e065de18a05400 GIT binary patch literal 386 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!n2Vh}LpV4%Za?&Y0OWEOctjQh zm0t&8MkkHg6+l7B64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1UT1AIbU zf%K|Xt2S-gv~lA`Ah{U~AdD?rw!lSz!ay!W7LCLzKJP(u8_;N(k|4ie24+PQQ!^V+ z-^{G+h09lN+qwI|xm$Pdzxwp!*WWnt!uLRRrJgR1ArXh)UN`4!aNuzXEIL=%xbwed zX66RnT;@xE>f#=say)Qj@h!*PZq@@E*sT~hytyc>;LyO(*w4t#u;Y|)!)MkHjtSct zdKpAMuQGFCN;oHd!=~}eCWezgu9X~Mdh*MWL*NJVgq79m%!$=nzbEkvRhKbuc(fzz TzhWgQ3>Z9J{an^LB{Ts5C|s&j literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/titlebar/floating_normal_inactive.png b/.config/awesome/iceys-theme/titlebar/floating_normal_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..e2bbdfa1793b1bff74d7a745e952778a672eaf3c GIT binary patch literal 237 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e=3*z$5DpHG+YkL80J)q69+AaB z<<~)&(Me-=1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWD>u0G|+7 zAiZVFmQ9;BZH58fK2>X=C~HZOUob;vR`w^6{TC+z1#CQB978;gCnrd-79g{GOjZ QKyw&8UHx3vIVCg!0PqV+WdHyG literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/titlebar/maximized_focus_active.png b/.config/awesome/iceys-theme/titlebar/maximized_focus_active.png new file mode 100644 index 0000000000000000000000000000000000000000..d7dffd75563da170dd3287f488c32aefb9289776 GIT binary patch literal 480 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!n2Vh}LpV4%Za?&Y0OWEOctjQh zm0t&8MkkHg6+l7B64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1Ty1AIbU zf%G#lcn$+kpFRaLA%a-Rebf3s0<{U01o;IsxVd|JdHcqvEnWTS@ssaAuWgoF!oa}D z?CIhd5^?zL^}Bq{3OuY2ZduN;xBl_Ze>b*zgU5-gF+-5F}_Tjl(lveY& z`4hkV)$=(zzt{FIyd5LC>+RgYPeSI6f!A2|4ZLo@U~&5?6QO+dxx9(wF3&UeuU7Hj jeyf_e=c@dYSqA#u-PN}}HZ4m61{H&+tDnm{r-UW|fWyvx literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/titlebar/maximized_focus_inactive.png b/.config/awesome/iceys-theme/titlebar/maximized_focus_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..844389f1fb02fae94cd7c715e7f28ed04c991b02 GIT binary patch literal 452 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e=3*z$5DpHG+YkL80J)q69+AaB z<<~)&(Me-=1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWD>)0G|+7 zAbtDx?Z;s7?Af#D&!0bi`V>wAMd09Y`*VAsYTl9{zhDM-6;)%?^7@93B}EAZxL z#D8JOB4PX5OFg{XU-niK2A)Ei3#ums_c)@Lyt*5T4Y0RQF&0oc7}a zP8<(eeRg+Ly!$LBKO;?W`Ml*aHA%CgJF4P}KeVpQf4GHD%juRvsDrRb%a^7QrrZLB zCGvj+Hp=H*Kk%(tnDrvd?L_X|+&uy+1#CWWeZMIZWBHvT>%aD^Khxdjm{430C7}Gki>Hy>kWKFhOM?ab0X>F}Vum|2Z-03v&D-f( VR(tv5bD;MbJYD@<);T3K0RRdpzFhzS literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/titlebar/maximized_normal_active.png b/.config/awesome/iceys-theme/titlebar/maximized_normal_active.png new file mode 100644 index 0000000000000000000000000000000000000000..a705f8164298c1f1741425effec9ad1d57ce37ed GIT binary patch literal 480 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!n2Vh}LpV4%Za?&Y0OWEOctjQh zm0t&8MkkHg6+l7B64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1Ty1AIbU zf%N9ho40J)vT4&M2m?X_MSu*f;OMt6Za{4UB|(0{3~uh8Uf#a(X-ii>di>=3&ug3I zmM}0dGJCo>hD02Gd;Kn7vjPw6gIkt!?5%(N^WV+wGBe0=m(J-!JFnJtZsQQTdWB`D z{d4Y_x0nsiPB)Tcc*7u5jl|@KtAwy}&KFp)Ez>#WI!%=kx<=91W%=d~2L! z3O<)}RVZ@le6HrxapL*#c|OA&0mf@zCo`>R6iRp@*SN5{lP6YMa+hP$3%8jIqkVYp z7NylZZvMnCfAxHh&hNFo3vb6r?s_{n@RN{vW8gJbeFLxCFIe1u%0wt%eJ*bzxy$p6 o{i{{{x8JHJ?zt+zWR`(`cX#z|k4?*xfI-FJ>FVdQ&MBb@0Q$tm4gdfE literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/titlebar/maximized_normal_inactive.png b/.config/awesome/iceys-theme/titlebar/maximized_normal_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..4c1ab1f91f3191b9f1324a7aebdc82fb5cf83baf GIT binary patch literal 452 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e=3*z$5DpHG+YkL80J)q69+AaB z<<~)&(Me-=1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWD>)0G|+7 zAiZtdwv8J%Zr;3k%a$#hHf;iuKsFEn*$@Uq#AfmyeV}UIk|4ie26h!yW7G2bhK?mm zmn|tdU<8!-?CIhd;&J@#rM4euN`b|i&(rCh^cHT zGT1Bd=4ZrzVaFn2``SxAyxU*)R!6f;5^H!hN8sufhG#7+{5Y3esi*K?Vv-P^)O=L; zU;do-;{r|`4_SS7cT~LlEG9oAO>p_V|7 zrVysw0)-{=e*`wl=UhMVty!4$BFpVW?%Uja3`fi?m=bO;U{JW`$l0)V{%$6Ps&_>n z`c^jnJ#G6Y{+;BRpV#ZZ_NzbB-R783To5Io{J@K+k=u|>?+8nS1^WR#hK^!}J2P*8 bc_z)<=~`BM`Qvk-_Zd80{an^LB{Ts5=8d)( literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/titlebar/minimize_focus.png b/.config/awesome/iceys-theme/titlebar/minimize_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..caaceb296dc2e49a723b425a62aa12b6cc060ce0 GIT binary patch literal 234 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e&H|6fVxatW5N34Jm|X!BWH0gb zb!ETL!6vN4lv}Np1Qe1E@Ck7R($AhfdkzLb1_S_k|NsAg{Cl4PP@1hI$S;_IJuCau zkH}&{GoT1#lDE4HN87!rRX~ojr;B5V$MNI@3D(64B0LfXp5EN9tcjVKejZ$RE^TNK zQDM!DVASL~m9f5Ifiy=|Fzall^eYEMT-ccwbLNQjFx_HgDAf=9bAA4*y+Gp_JYD@< J);T3K0RS~8P4fT% literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/titlebar/minimize_normal.png b/.config/awesome/iceys-theme/titlebar/minimize_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..36621d0f3993fb0739d99558b5b46838c3a87e41 GIT binary patch literal 225 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e&H|6fVxatW5N34Jm|X!BWH0gb zb!ETL!6vM#^Y6{ZETE7?fKP}kklws`^QKLkfFvCJ|NsB$-P_VYIku7@zhDOTtn5!e zB8vshfFg`Z-tI2!Vu>BEfgD>;7sn8f*71 zni+90AlTu;Y^@t27K>X{7b~zyym%oCRBge`kiI-@?}V!_n1BW`c)I$ztaD0e0sz}E BN7?`Y literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/titlebar/ontop_focus_active.png b/.config/awesome/iceys-theme/titlebar/ontop_focus_active.png new file mode 100644 index 0000000000000000000000000000000000000000..312c00ba8246608404568b1338cba9b264847bdc GIT binary patch literal 467 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!n2Vh}LpV4%Za?&Y0OWEOctjQh zm0t&8MkkHg6+l7B64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1S_1AIbU zf%O0X|F2%X`r^flmoHxeNg#Ok?Adb|fUuuFeF_l(G9YXq36vragzcG{3ba_QB*-tA zft5{6Tu0Z#)5|+HuDqkOt9!-DRa>@h+kf!PrOQ_yJbd){$&WvO6_zS{0d>stba4!c zIQ;hdNxmink=Dd55eGTv1URI=`)#ijJ!!L*rdsTr`t#GDOZNP-rEi5d;|rNk z?gnLH1&0O(#{VpA?|w2iShL?@xH0dX%W>a^>DiYIlz+Uf)xXZxFp=4f!HchgSs-5C zWhZBWbZ(%aZ8<~D4#jH>J~9T3AHK#m)*2dX@XU5m_P2V%W{JY_&xzP7Z c^O9+2*)B-3tX(;y7U)t2Pgg&ebxsLQ0C;ZdcK`qY literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/titlebar/ontop_focus_inactive.png b/.config/awesome/iceys-theme/titlebar/ontop_focus_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..a48e1c5c7a4b20a783fb8afe704616531d367039 GIT binary patch literal 604 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!n2Vh}LpV4%Za?&Y0OWEOctjQh zm0t&8MkkHg6+l7B64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1UH2l#}z z0_p!SaP{id`}glZe*F0L>(@ZWvuDqqKY#x6A@jx=l%tUoZnBGYcCBC$E5rsJOI@yt=Wu zjkBkhcVKvWUU5lfReSfO8FLn`TD@`SzWt{!T)TDu(c>rYKYafB&{yph(aa1vpBB}n zeXRMsX2$$kdzYon6Z`nI(4bs6Qo(@7|6RvB{(I^B{lDIxfBW*npT1k}eiu8sKK>)q z{hl9nUu8;}^tSHUm*g(b82$4*zw=5bhr@N}m&>H??`BfJ6=}bSLEs?+yTyS{ literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/titlebar/ontop_normal_active.png b/.config/awesome/iceys-theme/titlebar/ontop_normal_active.png new file mode 100644 index 0000000000000000000000000000000000000000..117a203c65f0de56854c427b6125a147c8c0aeba GIT binary patch literal 467 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!n2Vh}LpV4%Za?&Y0OWEOctjQh zm0t&8MkkHg6+l7B64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1S_1AIbU zf%KU(XI8CRwQk+IjT<*^*|KFT7;M_KY4hgIKrR{sA_yme3^;(OgmdvQzOkO|23o9E z666=mz{(~juA}SW>E#_8SKiUt)xBcnsx4c$?LTR)GTn8@tL;Kf(L zED$g6vXiqwIyX?zww$46hvGE`9~lG24_{*&YYmMxavE-D7(MgdGvn*|rtg_w{@w7? gTmdKI;Vst0GABY_5c6? literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/titlebar/ontop_normal_inactive.png b/.config/awesome/iceys-theme/titlebar/ontop_normal_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..d3a10c8a7d1f94a8f99dfbcda0e8338beef56657 GIT binary patch literal 604 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!n2Vh}LpV4%Za?&Y0OWEOctjQh zm0t&8MkkHg6+l7B64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1UH2l#}z z0_p$%|F2rLYXAQIaB}0ujqBI1-@JMAwr$&hYzSlP)~!JHmMvR=44?=QY}&L5NCHK` zJOme694HIq0!bi%C_^J5iXnoy)Szhra;Ido{{%YSrX(AeR0yWdN z0?j$^>Eaj?aro^tcd@1b9)^QWT^eE=w7d2;%bxsu{;8XMM#O~kZnZQ2o_VIu=$SM_ zpqE*oz*nT8v89+k zi|W!o)_h(wWB#nY%hKkFeSBJIP%a#)V8G-5uHzm5z4ZP5UvJO9eR<(e-z|5)iyd7b z|B>l_&yTvVGNnv&8?HB&zv)F;j$I0*KXLdZTpVB`;VQua{b|>XYbyB`ttSr zk6*w4{QdXQ>-P_!aZf#6977@wzrAvt?~s82OTgvo_X1V#_ik_b`@dd^Nz>xllUPQl zPjiZ9s(Z_|8;XifJ)dT^JzatO&4GDWuQzUG&`D{W!;q4~c>KsU`BU-EPtJVpcRb=c z&2m9UWYhPwul#yfrtxs!Fl7D1(Xl_RfH$Fm&wPp1qWK0E4}>PM@7i|!$^u!2;+A@&Q+O>Sd&5oo!9KPjrH;U8PhMs1gM6M3d=aetMz`PUzv1^1lKu>9!}IM3_H$92GL zgUZ*NJjYBH@R~{mF!r)NQS@fMG+_~A;)jb2-{%P$FJh7s^$28C4-WjbP0l+XkKj-jRa#!x(bdz}KXKaZx$_q+ zT)brIvYiLcU%qkY!NW&So<4i=>g~JtA3lEi{pat$NcD5TAZ8Twba4!cIQ(|<$uK5E z0as=wt;I@8N*A=wad8-(P*Kp>eCqfA{z7IUE1jU&=Q~c_{rc$My2)NG1`<5~yR7Sv ze2NvVIcCu))4+d@hnZoHq!PpW0@k#J9BB`E_Z-qapmk#35TB9V}k|LqfeI zH-D8u$lsSM=e@OF?-%-e`Cpmqm-=59Uwvnr@@LlJ`8^@BcQ<^ysCq2=kDtf?H~hcW z{Lk0DP@}kr`Sv^KrjFb;p}(BDVwd>j3d26B%k7e%pssQG?_9Np_n`+CvCB0c4bIuw zJ+uE!H1`?(|9+d?zVWALxL^PNu<6zNZ69`RzxS-WTS}w;uIKm0clY%c`@wonq;ZYAiBJSE=ovg+{an^LB{Ts5ij1~F literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/titlebar/sticky_normal_active.png b/.config/awesome/iceys-theme/titlebar/sticky_normal_active.png new file mode 100644 index 0000000000000000000000000000000000000000..bdb5595dbafe4cd35499dc8c638f26ce27ceb835 GIT binary patch literal 654 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!n2Vh}LpV4%Za?&Y0OWEOctjQh zm0t&8MkkHg6+l7B64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1Uf1o(uw z0_p$%|F2rL>dculKyv^7{XlZtwrx9h?AW?>>!wYcwrtt5apOiH8%S>6ym`Zh4M0I4 z7s!T)K-2)aK$Soe&H#!70gwwM(WKA>A<95HDFab2w0MF3aV`n+3ua(sW@Y2x6qS@$ zR8mn>*U-||HFFIJi%%^mEh}$soiu&soOuhEtysNw!gnPb5^?zLmE(Me3 z5!Y#!3pyg3zNdZV*Sj)}hx>*h>mQDe{b>cf2@QPaORN^nH?VjhG>LuJw&Pb8$TAeS z%==)U;q`5D8^eo0%LV*NQAG{^*m5>%yR4hYGi8hWtF+C({^%^Y=X{3cPmjQPUOzsr z17;gkzTV_HX0m|SR4Rb6m+gt7H}jTx9q@PtbS~la#1OAftM4;Lr9ujIUEO VV$V(cq5||VgQu&X%Q~loCIC1(MV9~o literal 0 HcmV?d00001 diff --git a/.config/awesome/iceys-theme/titlebar/sticky_normal_inactive.png b/.config/awesome/iceys-theme/titlebar/sticky_normal_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..a96b9b1951dee732d570ce3afe9512f9e4546d8f GIT binary patch literal 758 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!n2Vh}LpV4%Za?&Y0OWEOctjQh zm0t&8MkkHg6+l7B64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1Tk2Ka=y z0_lc^hE=Op?ccv2NN(G<4Z_&Db0?6!Wy_Y08#e+O8#ZiMzkWTCv3c|6ty{MO1%ZrB zn>N9@K$Q?SP!Pg~Fd%AxB0vU&4Iz<5fEpoOAOj8{h5)$`^*{z(1g?e>M&715=YjK=Z`^tC@X?c}&tANG`|kaRkDq@3`TH+Y{Twie83jFE977@w zzny$CjLA^Im6=Ivv67O~1+8;j97ZQp6f`!U`u)GZkXgt|Cn)y$j#GEPKDxJVvR8|N z1ke92>-r;~Vnu6?Sv1Nt@So#hW|$+X#IU}AHEkhB+C$zwhjb5Uo!B?|&@zAh8?{LX zi`V~`t+h5latSLXVq{@2A<-`S@8nRR%6Pl)W@4c{)R9*h3t z=kfmy|F1Rw^K~!OC@x~Y{m!|mBezZHFK4dUB|f>ruutl8yW}URYh3<2SFPcF=z&G- za*aoWb9Q#m?0*x@eMbMk-zK+j{OK9)*S|k(di8$Whh5w6J?rk4(x|`d`MvSo{XO$N t;~h86&tYL<|G#zi)9%_tpr`zPu$~iXT;pyc6afr+22WQ%mvv4FO#rh4ggO8K literal 0 HcmV?d00001 diff --git a/.config/awesome/rc.bak2.lua b/.config/awesome/rc.bak2.lua new file mode 100644 index 0000000..ffe59ce --- /dev/null +++ b/.config/awesome/rc.bak2.lua @@ -0,0 +1,580 @@ +-- If LuaRocks is installed, make sure that packages installed through it are +-- found (e.g. lgi). If LuaRocks is not installed, do nothing. +pcall(require, "luarocks.loader") + +-- Standard awesome library +local chosen_theme = "msjche" +local gears = require("gears") +local awful = require("awful") +require("awful.autofocus") +-- Widget and layout library +local wibox = require("wibox") +-- Theme handling library +local beautiful = require("beautiful") +-- Notification library +local naughty = require("naughty") +local menubar = require("menubar") +local hotkeys_popup = require("awful.hotkeys_popup") +-- Enable hotkeys help widget for VIM and other apps +-- when client with a matching name is opened: +require("awful.hotkeys_popup.keys") + +-- {{{ Error handling +-- Check if awesome encountered an error during startup and fell back to +-- another config (This code will only ever execute for the fallback config) +if awesome.startup_errors then + naughty.notify({ preset = naughty.config.presets.critical, + title = "Oops, there were errors during startup!", + text = awesome.startup_errors }) +end + +-- Handle runtime errors after startup +do + local in_error = false + awesome.connect_signal("debug::error", function (err) + -- Make sure we don't go into an endless error loop + if in_error then return end + in_error = true + + naughty.notify({ preset = naughty.config.presets.critical, + title = "Oops, an error happened!", + text = tostring(err) }) + in_error = false + end) +end +-- }}} + +-- {{{ Variable definitions +-- Themes define colours, icons, font and wallpapers. +beautiful.init(gears.filesystem.get_themes_dir() .. "default/theme.lua") + +-- This is used later as the default terminal and editor to run. +terminal = "wezterm" +editor = os.getenv("EDITOR") or "nvim" +editor_cmd = terminal .. " -e " .. editor + +-- Default modkey. +-- Usually, Mod4 is the key with a logo between Control and Alt. +-- If you do not like this or do not have such a key, +-- I suggest you to remap Mod4 to another key using xmodmap or other tools. +-- However, you can use another modifier like Mod1, but it may interact with others. +modkey = "Mod4" + +-- Table of layouts to cover with awful.layout.inc, order matters. +awful.layout.layouts = { + awful.layout.suit.floating, + awful.layout.suit.tile, + awful.layout.suit.tile.left, + awful.layout.suit.tile.bottom, + awful.layout.suit.tile.top, + awful.layout.suit.fair, + awful.layout.suit.fair.horizontal, + awful.layout.suit.spiral, + awful.layout.suit.spiral.dwindle, + awful.layout.suit.max, + awful.layout.suit.max.fullscreen, + awful.layout.suit.magnifier, + awful.layout.suit.corner.nw, + -- awful.layout.suit.corner.ne, + -- awful.layout.suit.corner.sw, + -- awful.layout.suit.corner.se, +} +-- }}} + + +local theme_path = string.format("%s/.config/awesome/themes/%s/theme.lua", os.getenv("HOME"), chosen_theme) +naughty.notify({text = 'Debug Message: '.. theme_path}) +--beautiful.init(theme_path) + +-- {{{ Menu +-- Create a launcher widget and a main menu +myawesomemenu = { + { "hotkeys", function() hotkeys_popup.show_help(nil, awful.screen.focused()) end }, + { "manual", terminal .. " -e man awesome" }, + { "edit config", editor_cmd .. " " .. awesome.conffile }, + { "restart", awesome.restart }, + { "quit", function() awesome.quit() end }, +} + +mymainmenu = awful.menu({ items = { { "awesome", myawesomemenu, beautiful.awesome_icon }, + { "open terminal", terminal } + } + }) + +mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon, + menu = mymainmenu }) + +-- Menubar configuration +menubar.utils.terminal = terminal -- Set the terminal for applications that require it +-- }}} + +-- Keyboard map indicator and switcher +mykeyboardlayout = awful.widget.keyboardlayout() + +-- {{{ Wibar +-- Create a textclock widget +mytextclock = wibox.widget.textclock() + +-- Create a wibox for each screen and add it +local taglist_buttons = gears.table.join( + awful.button({ }, 1, function(t) t:view_only() end), + awful.button({ modkey }, 1, function(t) + if client.focus then + client.focus:move_to_tag(t) + end + end), + awful.button({ }, 3, awful.tag.viewtoggle), + awful.button({ modkey }, 3, function(t) + if client.focus then + client.focus:toggle_tag(t) + end + end), + awful.button({ }, 4, function(t) awful.tag.viewnext(t.screen) end), + awful.button({ }, 5, function(t) awful.tag.viewprev(t.screen) end) + ) + +local tasklist_buttons = gears.table.join( + awful.button({ }, 1, function (c) + if c == client.focus then + c.minimized = true + else + c:emit_signal( + "request::activate", + "tasklist", + {raise = true} + ) + end + end), + awful.button({ }, 3, function() + awful.menu.client_list({ theme = { width = 250 } }) + end), + awful.button({ }, 4, function () + awful.client.focus.byidx(1) + end), + awful.button({ }, 5, function () + awful.client.focus.byidx(-1) + end)) + +local function set_wallpaper(s) + -- Wallpaper + if beautiful.wallpaper then + local wallpaper = beautiful.wallpaper + -- If wallpaper is a function, call it with the screen + if type(wallpaper) == "function" then + wallpaper = wallpaper(s) + end + gears.wallpaper.maximized(wallpaper, s, true) + end +end + +-- Re-set wallpaper when a screen's geometry changes (e.g. different resolution) +screen.connect_signal("property::geometry", set_wallpaper) + +awful.screen.connect_for_each_screen(function(s) + -- Wallpaper + set_wallpaper(s) + + -- Each screen has its own tag table. + awful.tag({ "1", "2", "3", "4", "5", "6", "7", "8", "9" }, s, awful.layout.layouts[1]) + + -- Create a promptbox for each screen + s.mypromptbox = awful.widget.prompt() + -- Create an imagebox widget which will contain an icon indicating which layout we're using. + -- We need one layoutbox per screen. + s.mylayoutbox = awful.widget.layoutbox(s) + s.mylayoutbox:buttons(gears.table.join( + awful.button({ }, 1, function () awful.layout.inc( 1) end), + awful.button({ }, 3, function () awful.layout.inc(-1) end), + awful.button({ }, 4, function () awful.layout.inc( 1) end), + awful.button({ }, 5, function () awful.layout.inc(-1) end))) + -- Create a taglist widget + s.mytaglist = awful.widget.taglist { + screen = s, + filter = awful.widget.taglist.filter.all, + buttons = taglist_buttons + } + + -- Create a tasklist widget + s.mytasklist = awful.widget.tasklist { + screen = s, + filter = awful.widget.tasklist.filter.currenttags, + buttons = tasklist_buttons + } + + -- Create the wibox + s.mywibox = awful.wibar({ position = "top", screen = s }) + + -- Add widgets to the wibox + s.mywibox:setup { + layout = wibox.layout.align.horizontal, + { -- Left widgets + layout = wibox.layout.fixed.horizontal, + mylauncher, + s.mytaglist, + s.mypromptbox, + }, + s.mytasklist, -- Middle widget + { -- Right widgets + layout = wibox.layout.fixed.horizontal, + mykeyboardlayout, + wibox.widget.systray(), + mytextclock, + s.mylayoutbox, + }, + } +end) +-- }}} + +-- {{{ Mouse bindings +root.buttons(gears.table.join( + awful.button({ }, 3, function () mymainmenu:toggle() end), + awful.button({ }, 4, awful.tag.viewnext), + awful.button({ }, 5, awful.tag.viewprev) +)) +-- }}} + +-- {{{ Key bindings +globalkeys = gears.table.join( + awful.key({ modkey, }, "s", hotkeys_popup.show_help, + {description="show help", group="awesome"}), + awful.key({ modkey, }, "Left", awful.tag.viewprev, + {description = "view previous", group = "tag"}), + awful.key({ modkey, }, "Right", awful.tag.viewnext, + {description = "view next", group = "tag"}), + awful.key({ modkey, }, "Escape", awful.tag.history.restore, + {description = "go back", group = "tag"}), + + awful.key({ modkey, }, "j", + function () + awful.client.focus.byidx( 1) + end, + {description = "focus next by index", group = "client"} + ), + awful.key({ modkey, }, "k", + function () + awful.client.focus.byidx(-1) + end, + {description = "focus previous by index", group = "client"} + ), + awful.key({ modkey, }, "w", function () mymainmenu:show() end, + {description = "show main menu", group = "awesome"}), + + -- Layout manipulation + awful.key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx( 1) end, + {description = "swap with next client by index", group = "client"}), + awful.key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx( -1) end, + {description = "swap with previous client by index", group = "client"}), + awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative( 1) end, + {description = "focus the next screen", group = "screen"}), + awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative(-1) end, + {description = "focus the previous screen", group = "screen"}), + awful.key({ modkey, }, "u", awful.client.urgent.jumpto, + {description = "jump to urgent client", group = "client"}), + awful.key({ modkey, }, "Tab", + function () + awful.client.focus.history.previous() + if client.focus then + client.focus:raise() + end + end, + {description = "go back", group = "client"}), + + -- Standard program + awful.key({ modkey, }, "Return", function () awful.spawn(terminal) end, + {description = "open a terminal", group = "launcher"}), + awful.key({ modkey, "Control" }, "r", awesome.restart, + {description = "reload awesome", group = "awesome"}), + awful.key({ modkey, "Shift" }, "q", awesome.quit, + {description = "quit awesome", group = "awesome"}), + + awful.key({ modkey, }, "l", function () awful.tag.incmwfact( 0.05) end, + {description = "increase master width factor", group = "layout"}), + awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end, + {description = "decrease master width factor", group = "layout"}), + awful.key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster( 1, nil, true) end, + {description = "increase the number of master clients", group = "layout"}), + awful.key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1, nil, true) end, + {description = "decrease the number of master clients", group = "layout"}), + awful.key({ modkey, "Control" }, "h", function () awful.tag.incncol( 1, nil, true) end, + {description = "increase the number of columns", group = "layout"}), + awful.key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1, nil, true) end, + {description = "decrease the number of columns", group = "layout"}), + awful.key({ modkey, }, "space", function () awful.layout.inc( 1) end, + {description = "select next", group = "layout"}), + awful.key({ modkey, "Shift" }, "space", function () awful.layout.inc(-1) end, + {description = "select previous", group = "layout"}), + + awful.key({ modkey, "Control" }, "n", + function () + local c = awful.client.restore() + -- Focus restored client + if c then + c:emit_signal( + "request::activate", "key.unminimize", {raise = true} + ) + end + end, + {description = "restore minimized", group = "client"}), + + -- Prompt + awful.key({ modkey }, "r", function () awful.screen.focused().mypromptbox:run() end, + {description = "run prompt", group = "launcher"}), + + awful.key({ modkey }, "d", function () os.execute("rofi -show drun") end, {description = "rofi drun", group = "launcher"}), + + awful.key({ modkey }, "x", + function () + awful.prompt.run { + prompt = "Run Lua code: ", + textbox = awful.screen.focused().mypromptbox.widget, + exe_callback = awful.util.eval, + history_path = awful.util.get_cache_dir() .. "/history_eval" + } + end, + {description = "lua execute prompt", group = "awesome"}), + -- Menubar + awful.key({ modkey }, "p", function() menubar.show() end, + {description = "show the menubar", group = "launcher"}) +) + +clientkeys = gears.table.join( + awful.key({ modkey, }, "f", + function (c) + c.fullscreen = not c.fullscreen + c:raise() + end, + {description = "toggle fullscreen", group = "client"}), + awful.key({ modkey, }, "q", function (c) c:kill() end, + {description = "close", group = "client"}), + awful.key({ modkey, "Control" }, "space", awful.client.floating.toggle , + {description = "toggle floating", group = "client"}), + awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end, + {description = "move to master", group = "client"}), + awful.key({ modkey, }, "o", function (c) c:move_to_screen() end, + {description = "move to screen", group = "client"}), + awful.key({ modkey, }, "t", function (c) c.ontop = not c.ontop end, + {description = "toggle keep on top", group = "client"}), + awful.key({ modkey, }, "n", + function (c) + -- The client currently has the input focus, so it cannot be + -- minimized, since minimized clients can't have the focus. + c.minimized = true + end , + {description = "minimize", group = "client"}), + awful.key({ modkey, }, "m", + function (c) + c.maximized = not c.maximized + c:raise() + end , + {description = "(un)maximize", group = "client"}), + awful.key({ modkey, "Control" }, "m", + function (c) + c.maximized_vertical = not c.maximized_vertical + c:raise() + end , + {description = "(un)maximize vertically", group = "client"}), + awful.key({ modkey, "Shift" }, "m", + function (c) + c.maximized_horizontal = not c.maximized_horizontal + c:raise() + end , + {description = "(un)maximize horizontally", group = "client"}) +) + +-- Bind all key numbers to tags. +-- Be careful: we use keycodes to make it work on any keyboard layout. +-- This should map on the top row of your keyboard, usually 1 to 9. +for i = 1, 9 do + globalkeys = gears.table.join(globalkeys, + -- View tag only. + awful.key({ modkey }, "#" .. i + 9, + function () + local screen = awful.screen.focused() + local tag = screen.tags[i] + if tag then + tag:view_only() + end + end, + {description = "view tag #"..i, group = "tag"}), + -- Toggle tag display. + awful.key({ modkey, "Control" }, "#" .. i + 9, + function () + local screen = awful.screen.focused() + local tag = screen.tags[i] + if tag then + awful.tag.viewtoggle(tag) + end + end, + {description = "toggle tag #" .. i, group = "tag"}), + -- Move client to tag. + awful.key({ modkey, "Shift" }, "#" .. i + 9, + function () + if client.focus then + local tag = client.focus.screen.tags[i] + if tag then + client.focus:move_to_tag(tag) + end + end + end, + {description = "move focused client to tag #"..i, group = "tag"}), + -- Toggle tag on focused client. + awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9, + function () + if client.focus then + local tag = client.focus.screen.tags[i] + if tag then + client.focus:toggle_tag(tag) + end + end + end, + {description = "toggle focused client on tag #" .. i, group = "tag"}) + ) +end + +clientbuttons = gears.table.join( + awful.button({ }, 1, function (c) + c:emit_signal("request::activate", "mouse_click", {raise = true}) + end), + awful.button({ modkey }, 1, function (c) + c:emit_signal("request::activate", "mouse_click", {raise = true}) + awful.mouse.client.move(c) + end), + awful.button({ modkey }, 3, function (c) + c:emit_signal("request::activate", "mouse_click", {raise = true}) + awful.mouse.client.resize(c) + end) +) + +-- Set keys +root.keys(globalkeys) +-- }}} + +-- {{{ Rules +-- Rules to apply to new clients (through the "manage" signal). +awful.rules.rules = { + -- All clients will match this rule. + { rule = { }, + properties = { border_width = beautiful.border_width, + border_color = beautiful.border_normal, + focus = awful.client.focus.filter, + raise = true, + keys = clientkeys, + buttons = clientbuttons, + screen = awful.screen.preferred, + placement = awful.placement.no_overlap+awful.placement.no_offscreen + } + }, + + -- Floating clients. + { rule_any = { + instance = { + "DTA", -- Firefox addon DownThemAll. + "copyq", -- Includes session name in class. + "pinentry", + }, + class = { + "Arandr", + "Blueman-manager", + "Gpick", + "Kruler", + "MessageWin", -- kalarm. + "Sxiv", + "Tor Browser", -- Needs a fixed window size to avoid fingerprinting by screen size. + "Wpa_gui", + "veromix", + "xtightvncviewer"}, + + -- Note that the name property shown in xprop might be set slightly after creation of the client + -- and the name shown there might not match defined rules here. + name = { + "Event Tester", -- xev. + }, + role = { + "AlarmWindow", -- Thunderbird's calendar. + "ConfigManager", -- Thunderbird's about:config. + "pop-up", -- e.g. Google Chrome's (detached) Developer Tools. + } + }, properties = { floating = true }}, + + -- Add titlebars to normal clients and dialogs + { rule_any = {type = { "normal", "dialog" } + }, properties = { titlebars_enabled = false } + }, + + -- Set Firefox to always map on the tag named "2" on screen 1. + -- { rule = { class = "Firefox" }, + -- properties = { screen = 1, tag = "2" } }, +} +-- }}} + +-- {{{ Signals +-- Signal function to execute when a new client appears. +client.connect_signal("manage", function (c) + -- Set the windows at the slave, + -- i.e. put it at the end of others instead of setting it master. + -- if not awesome.startup then awful.client.setslave(c) end + + if awesome.startup + and not c.size_hints.user_position + and not c.size_hints.program_position then + -- Prevent clients from being unreachable after screen count changes. + awful.placement.no_offscreen(c) + end +end) + +-- Add a titlebar if titlebars_enabled is set to true in the rules. +client.connect_signal("request::titlebars", function(c) + -- buttons for the titlebar + local buttons = gears.table.join( + awful.button({ }, 1, function() + c:emit_signal("request::activate", "titlebar", {raise = true}) + awful.mouse.client.move(c) + end), + awful.button({ }, 3, function() + c:emit_signal("request::activate", "titlebar", {raise = true}) + awful.mouse.client.resize(c) + end) + ) + + awful.titlebar(c) : setup { + { -- Left + awful.titlebar.widget.iconwidget(c), + buttons = buttons, + layout = wibox.layout.fixed.horizontal + }, + { -- Middle + { -- Title + align = "center", + widget = awful.titlebar.widget.titlewidget(c) + }, + buttons = buttons, + layout = wibox.layout.flex.horizontal + }, + { -- Right + awful.titlebar.widget.floatingbutton (c), + awful.titlebar.widget.maximizedbutton(c), + awful.titlebar.widget.stickybutton (c), + awful.titlebar.widget.ontopbutton (c), + awful.titlebar.widget.closebutton (c), + layout = wibox.layout.fixed.horizontal() + }, + layout = wibox.layout.align.horizontal + } +end) + +-- Enable sloppy focus, so that focus follows mouse. +client.connect_signal("mouse::enter", function(c) + c:emit_signal("request::activate", "mouse_enter", {raise = false}) +end) + +client.connect_signal("focus", function(c) c.border_color = beautiful.border_focus end) +client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end) +-- }}} + + +-- autostart applets +awful.spawn.with_shell("xcompmgr") +awful.spawn.with_shell("xrandr --dpi 90") +awful.spawn.with_shell("xrandr --output Virtual-1 --mode 1920x1080") +awful.spawn.with_shell("wezterm -e ~/stuff/scripts/system/task.sh") +awful.spawn.with_shell("sleep 0.5s && nitrogen --restore") diff --git a/.config/awesome/rc.lua b/.config/awesome/rc.lua new file mode 100644 index 0000000..c2c4e1e --- /dev/null +++ b/.config/awesome/rc.lua @@ -0,0 +1,652 @@ +-- If LuaRocks is installed, make sure that packages installed through it are +-- found (e.g. lgi). If LuaRocks is not installed, do nothing. +pcall(require, "luarocks.loader") + +-- Standard awesome library +local gears = require("gears") +local awful = require("awful") +require("awful.autofocus") +-- Widget and layout library +local wibox = require("wibox") +-- Theme handling library +local beautiful = require("beautiful") +-- Notification library +local naughty = require("naughty") +local menubar = require("menubar") +local hotkeys_popup = require("awful.hotkeys_popup") +-- Enable hotkeys help widget for VIM and other apps +-- when client with a matching name is opened: +require("awful.hotkeys_popup.keys") + +local HOMEDIR="/home/iceyrazor/" + + + +local show_desktop = false +function show_my_desktop() + if show_desktop then + for _, c in ipairs(client.get()) do + c:emit_signal( + "request::activate", "key.unminimize", {raise = true} + ) + end + show_desktop = false + else + for _, c in ipairs(client.get()) do + c.minimized = true + end + show_desktop = true + end +end + +--auto switch to tag with clients if no current clients exist in current tag +client.connect_signal("unmanage", function(c) + local t = c.first_tag or awful.screen.focused().selected_tag + for _, cl in ipairs(t:clients()) do + if cl ~= c then + return + end + end + for _, t in ipairs(awful.screen.focused().tags) do + if #t:clients() > 0 then + t:view_only() + return + end + end +end) + + +-- {{{ Error handling +-- Check if awesome encountered an error during startup and fell back to +-- another config (This code will only ever execute for the fallback config) +if awesome.startup_errors then + naughty.notify({ preset = naughty.config.presets.critical, + title = "Oops, there were errors during startup!", + text = awesome.startup_errors }) +end + +-- Handle runtime errors after startup +do + local in_error = false + awesome.connect_signal("debug::error", function (err) + -- Make sure we don't go into an endless error loop + if in_error then return end + in_error = true + + naughty.notify({ preset = naughty.config.presets.critical, + title = "Oops, an error happened!", + text = tostring(err) }) + in_error = false + end) +end +-- }}} + +-- {{{ Variable definitions +-- Themes define colours, icons, font and wallpapers. +--beautiful.init(gears.filesystem.get_themes_dir() .. "openSUSE/theme.lua") +beautiful.init(gears.filesystem.get_configuration_dir() .. "iceys-theme/theme.lua") + + +-- This is used later as the default terminal and editor to run. +terminal = "wezterm" +editor = os.getenv("EDITOR") or "nvim" +editor_cmd = terminal .. " -e " .. editor + +-- Default modkey. +-- Usually, Mod4 is the key with a logo between Control and Alt. +-- If you do not like this or do not have such a key, +-- I suggest you to remap Mod4 to another key using xmodmap or other tools. +-- However, you can use another modifier like Mod1, but it may interact with others. +modkey = "Mod4" + +-- Table of layouts to cover with awful.layout.inc, order matters. +awful.layout.layouts = { + awful.layout.suit.floating, + awful.layout.suit.tile, + awful.layout.suit.tile.left, + awful.layout.suit.tile.bottom, + awful.layout.suit.tile.top, + awful.layout.suit.fair, + awful.layout.suit.fair.horizontal, + awful.layout.suit.spiral, + awful.layout.suit.spiral.dwindle, + awful.layout.suit.max, + awful.layout.suit.max.fullscreen, + awful.layout.suit.magnifier, + awful.layout.suit.corner.nw, + -- awful.layout.suit.corner.ne, + -- awful.layout.suit.corner.sw, + -- awful.layout.suit.corner.se, +} +-- }}} + + + +-- {{{ Menu +-- Create a launcher widget and a main menu +myawesomemenu = { + { "hotkeys", function() hotkeys_popup.show_help(nil, awful.screen.focused()) end }, + { "manual", terminal .. " -e man awesome" }, + { "edit config", editor_cmd .. " " .. awesome.conffile }, + { "restart", awesome.restart }, + { "quit", function() awesome.quit() end }, +} + +mymainmenu = awful.menu({ items = { { "awesome", myawesomemenu, beautiful.awesome_icon }, + { "open terminal", terminal } + } + }) + +mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon, + menu = mymainmenu }) + +-- Menubar configuration +menubar.utils.terminal = terminal -- Set the terminal for applications that require it +-- }}} + +-- Keyboard map indicator and switcher +mykeyboardlayout = awful.widget.keyboardlayout() + +-- {{{ Wibar +-- Create a textclock widget +mytextclock = wibox.widget.textclock("%a %m/%d/%Y %I:%M%p") + +-- Create a wibox for each screen and add it +local taglist_buttons = gears.table.join( + awful.button({ }, 1, function(t) t:view_only() end), + awful.button({ modkey }, 1, function(t) + if client.focus then + client.focus:move_to_tag(t) + end + end), + awful.button({ }, 3, awful.tag.viewtoggle), + awful.button({ modkey }, 3, function(t) + if client.focus then + client.focus:toggle_tag(t) + end + end), + awful.button({ }, 4, function(t) awful.tag.viewnext(t.screen) end), + awful.button({ }, 5, function(t) awful.tag.viewprev(t.screen) end) + ) + +local tasklist_buttons = gears.table.join( + awful.button({ }, 1, function (c) + if c == client.focus then + c.minimized = true + else + c:emit_signal( + "request::activate", + "tasklist", + {raise = true} + ) + end + end), + awful.button({ }, 3, function() + awful.menu.client_list({ theme = { width = 250 } }) + end), + awful.button({ }, 4, function () + awful.client.focus.byidx(1) + end), + awful.button({ }, 5, function () + awful.client.focus.byidx(-1) + end)) + +local function set_wallpaper(s) + -- Wallpaper + if beautiful.wallpaper then + local wallpaper = beautiful.wallpaper + -- If wallpaper is a function, call it with the screen + if type(wallpaper) == "function" then + wallpaper = wallpaper(s) + end + gears.wallpaper.maximized(wallpaper, s, true) + end +end + +-- Re-set wallpaper when a screen's geometry changes (e.g. different resolution) +screen.connect_signal("property::geometry", set_wallpaper) + +awful.screen.connect_for_each_screen(function(s) + -- Wallpaper + set_wallpaper(s) + + -- Each screen has its own tag table. + --awful.tag({ "1", "2", "3", "4", "5", "6", "7", "8", "9" }, s, awful.layout.layouts[2]) + awful.tag({ "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  ", "  " }, s, awful.layout.layouts[2]) + + -- Create a promptbox for each screen + s.mypromptbox = awful.widget.prompt() + -- Create an imagebox widget which will contain an icon indicating which layout we're using. + -- We need one layoutbox per screen. + s.mylayoutbox = awful.widget.layoutbox(s) + s.mylayoutbox:buttons(gears.table.join( + awful.button({ }, 1, function () awful.layout.inc( 1) end), + awful.button({ }, 3, function () awful.layout.inc(-1) end), + awful.button({ }, 4, function () awful.layout.inc( 1) end), + awful.button({ }, 5, function () awful.layout.inc(-1) end))) + -- Create a taglist widget + s.mytaglist = awful.widget.taglist { + screen = s, + filter = awful.widget.taglist.filter.all, + buttons = taglist_buttons + } + + -- Create a tasklist widget + s.mytasklist = awful.widget.tasklist { + screen = s, + filter = awful.widget.tasklist.filter.currenttags, + buttons = tasklist_buttons + } + + -- Create the wibox + s.mywibox = awful.wibar({ position = "bottom", screen = s , height = 20}) + + -- Add widgets to the wibox + s.mywibox:setup { + layout = wibox.layout.align.horizontal, + { -- Left widgets + layout = wibox.layout.fixed.horizontal, + mylauncher, + s.mytaglist, + s.mypromptbox, + }, + s.mytasklist, -- Middle widget + { -- Right widgets + layout = wibox.layout.fixed.horizontal, + mykeyboardlayout, + awful.widget.watch(HOMEDIR..'stuff/scripts/system/stbar/stbar-awesome.sh', 2), + mytextclock, + wibox.widget.systray(), + s.mylayoutbox, + }, + } +end) + +local month_calendar = awful.widget.calendar_popup.month() +month_calendar:attach( mytextclock, "br" ) +--mytextclock:connect_signal("button::press",function () +--end) + +screen[2]:fake_resize(1920,0,1790,1006) +-- }}} + +-- {{{ Mouse bindings +root.buttons(gears.table.join( + awful.button({ }, 3, function () mymainmenu:toggle() end), + awful.button({ }, 4, awful.tag.viewnext), + awful.button({ }, 5, awful.tag.viewprev) +)) +-- }}} + +-- {{{ Key bindings +globalkeys = gears.table.join( + awful.key({ modkey, }, "F1", hotkeys_popup.show_help, + {description="show help", group="awesome"}), + awful.key({ modkey, }, "b", awful.tag.viewprev, + {description = "view previous", group = "tag"}), + awful.key({ modkey, }, "n", awful.tag.viewnext, + {description = "view next", group = "tag"}), + awful.key({ modkey, }, "Escape", awful.tag.history.restore, + {description = "go back", group = "tag"}), + + awful.key({ modkey, }, "j", + function () + awful.client.focus.byidx( 1) + end, + {description = "focus next by index", group = "client"} + ), + awful.key({ modkey, }, "k", + function () + awful.client.focus.byidx(-1) + end, + {description = "focus previous by index", group = "client"} + ), + awful.key({ modkey, }, "w", function () mymainmenu:show() end, + {description = "show main menu", group = "awesome"}), + + -- Layout manipulation + awful.key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx( 1) end, + {description = "swap with next client by index", group = "client"}), + awful.key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx( -1) end, + {description = "swap with previous client by index", group = "client"}), + awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative( 1) end, + {description = "focus the next screen", group = "screen"}), + awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative(-1) end, + {description = "focus the previous screen", group = "screen"}), + awful.key({ modkey, }, "u", awful.client.urgent.jumpto, + {description = "jump to urgent client", group = "client"}), + awful.key({ modkey, }, "Tab", + function () + awful.client.focus.history.previous() + if client.focus then + client.focus:raise() + end + end, + {description = "go back", group = "client"}), + + -- Standard program + awful.key({ modkey, }, "Return", function () awful.spawn(terminal) end, + {description = "open a terminal", group = "launcher"}), + awful.key({ modkey, "Control" }, "r", awesome.restart, + {description = "reload awesome", group = "awesome"}), + awful.key({ modkey, "Shift" }, "q", awesome.quit, + {description = "quit awesome", group = "awesome"}), + + awful.key({ modkey, "Shift" }, "o", show_my_desktop, {description = "show desktop", group = "awesome"}), + + awful.key({ modkey, }, "l", function () awful.tag.incmwfact( 0.05) end, + {description = "increase master width factor", group = "layout"}), + awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end, + {description = "decrease master width factor", group = "layout"}), + awful.key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster( 1, nil, true) end, + {description = "increase the number of master clients", group = "layout"}), + awful.key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1, nil, true) end, + {description = "decrease the number of master clients", group = "layout"}), + awful.key({ modkey, "Control" }, "h", function () awful.tag.incncol( 1, nil, true) end, + {description = "increase the number of columns", group = "layout"}), + awful.key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1, nil, true) end, + {description = "decrease the number of columns", group = "layout"}), + awful.key({ modkey, "Control" }, "space", function () awful.layout.inc( 1) end, + {description = "select next", group = "layout"}), + awful.key({ modkey, "Shift" }, "space", function () awful.layout.inc(-1) end, + {description = "select previous", group = "layout"}), + + awful.key({ modkey, "Shift", "Control" }, "n", + function () + local c = awful.client.restore() + -- Focus restored client + if c then + c:emit_signal( + "request::activate", "key.unminimize", {raise = true} + ) + end + end, + {description = "restore minimized", group = "client"}), + + -- Prompt + awful.key({ modkey }, "r", function () awful.screen.focused().mypromptbox:run() end, + {description = "run prompt", group = "launcher"}), + + awful.key({ modkey }, "d", function () os.execute("rofi -show drun") end, {description = "rofi drun", group = "launcher"}), + + awful.key({ modkey }, "x", + function () + awful.prompt.run { + prompt = "Run Lua code: ", + textbox = awful.screen.focused().mypromptbox.widget, + exe_callback = awful.util.eval, + history_path = awful.util.get_cache_dir() .. "/history_eval" + } + end, + {description = "lua execute prompt", group = "awesome"}), + -- Menubar + awful.key({ modkey }, "p", function() menubar.show() end, + {description = "show the menubar", group = "launcher"}) +) + +clientkeys = gears.table.join( + awful.key({ modkey, }, "f", + function (c) + c.fullscreen = not c.fullscreen + c:raise() + end, + {description = "toggle fullscreen", group = "client"}), + awful.key({ modkey, }, "q", function (c) c:kill() end, + {description = "close", group = "client"}), + awful.key({ modkey, }, "space", awful.client.floating.toggle , + {description = "toggle floating", group = "client"}), + awful.key({ modkey, }, "z", function (c) c:swap(awful.client.getmaster()) end, + {description = "move to master", group = "client"}), + awful.key({ modkey, }, "o", function (c) c:move_to_screen() end, + {description = "move to screen", group = "client"}), + awful.key({ modkey, }, "t", function (c) c.ontop = not c.ontop end, + {description = "toggle keep on top", group = "client"}), + awful.key({ modkey, "Shift" }, "n", + function (c) + -- The client currently has the input focus, so it cannot be + -- minimized, since minimized clients can't have the focus. + c.minimized = true + end , + {description = "minimize", group = "client"}), + awful.key({ modkey, }, "m", + function (c) + c.maximized = not c.maximized + c:raise() + end , + {description = "(un)maximize", group = "client"}), + awful.key({ modkey, "Control" }, "m", + function (c) + c.maximized_vertical = not c.maximized_vertical + c:raise() + end , + {description = "(un)maximize vertically", group = "client"}), + awful.key({ modkey, "Shift" }, "m", + function (c) + c.maximized_horizontal = not c.maximized_horizontal + c:raise() + end , + {description = "(un)maximize horizontally", group = "client"}), + + awful.key({ modkey }, 0, + function() + local screen = awful.screen.focused() + for i = 1,9 do + local tag = screen.tags[i] + if tag and tag.selected==false then + awful.tag.viewtoggle(tag) + end + end + end, + {description = "view all tags", group = "tag"}) +) + +-- Bind all key numbers to tags. +-- Be careful: we use keycodes to make it work on any keyboard layout. +-- This should map on the top row of your keyboard, usually 1 to 9. +for i = 1, 9 do + globalkeys = gears.table.join(globalkeys, + -- View tag only. + awful.key({ modkey }, "#" .. i + 9, + function () + local screen = awful.screen.focused() + local tag = screen.tags[i] + if tag then + tag:view_only() + end + end, + {description = "view tag #"..i, group = "tag"}), + -- Toggle tag display. + awful.key({ modkey, "Control" }, "#" .. i + 9, + function () + local screen = awful.screen.focused() + local tag = screen.tags[i] + if tag then + awful.tag.viewtoggle(tag) + end + end, + {description = "toggle tag #" .. i, group = "tag"}), + -- Move client to tag. + awful.key({ modkey, "Shift" }, "#" .. i + 9, + function () + if client.focus then + local tag = client.focus.screen.tags[i] + if tag then + client.focus:move_to_tag(tag) + end + end + end, + {description = "move focused client to tag #"..i, group = "tag"}), + -- Toggle tag on focused client. + awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9, + function () + if client.focus then + local tag = client.focus.screen.tags[i] + if tag then + client.focus:toggle_tag(tag) + end + end + end, + {description = "toggle focused client on tag #" .. i, group = "tag"}) + ) +end + +clientbuttons = gears.table.join( + awful.button({ }, 1, function (c) + c:emit_signal("request::activate", "mouse_click", {raise = true}) + end), + awful.button({modkey}, 1, function (c) + c:emit_signal("request::activate", "mouse_click", {raise = true}) + awful.mouse.client.move(c) + end), + awful.button({modkey}, 3, function (c) + c:emit_signal("request::activate", "mouse_click", {raise = true}) + awful.mouse.client.resize(c, "bottomright") --corner bonked + end) +) + +-- Set keys +root.keys(globalkeys) +-- }}} + + +-- {{{ Rules +-- Rules to apply to new clients (through the "manage" signal). +awful.rules.rules = { + -- All clients will match this rule. + { rule = { }, + properties = { border_width = beautiful.border_width, + border_color = beautiful.border_normal, + focus = awful.client.focus.filter, + raise = true, + keys = clientkeys, + buttons = clientbuttons, + screen = awful.screen.preferred, + placement = awful.placement.no_overlap+awful.placement.no_offscreen + } + }, + + -- Floating clients. + { rule_any = { + instance = { + "DTA", -- Firefox addon DownThemAll. + "copyq", -- Includes session name in class. + "pinentry", + }, + class = { + "Arandr", + "Blueman-manager", + "Gpick", + "steam", + "Kruler", + "MessageWin", -- kalarm. + "Sxiv", + "Tor Browser", -- Needs a fixed window size to avoid fingerprinting by screen size. + "Wpa_gui", + "Pcmanfm", + "veromix", + "xtightvncviewer"}, + + -- Note that the name property shown in xprop might be set slightly after creation of the client + -- and the name shown there might not match defined rules here. + name = { + "Event Tester", -- xev. + }, + role = { + "AlarmWindow", -- Thunderbird's calendar. + "ConfigManager", -- Thunderbird's about:config. + "pop-up", -- e.g. Google Chrome's (detached) Developer Tools. + } + }, properties = { floating = true }}, + + -- Add titlebars to normal clients and dialogs + { rule_any = {type = { "normal", "dialog" } + }, properties = { titlebars_enabled = false } + }, + + { rule_any = { + class = { "Mumble", "Gajim", "vesktop" } + }, + properties = { floating = true, screen = 2 } + }, + + { rule_any = { + class = { "steam_app*" } + }, + properties = { border_width = 0 } + } + + -- Set Firefox to always map on the tag named "2" on screen 1. + -- { rule = { class = "Firefox" }, + -- properties = { screen = 1, tag = "2" } }, +} +-- }}} + +-- {{{ Signals +-- Signal function to execute when a new client appears. +client.connect_signal("manage", function (c) + -- Set the windows at the slave, + -- i.e. put it at the end of others instead of setting it master. + -- if not awesome.startup then awful.client.setslave(c) end + + if awesome.startup + and not c.size_hints.user_position + and not c.size_hints.program_position then + -- Prevent clients from being unreachable after screen count changes. + awful.placement.no_offscreen(c) + end +end) + +-- Add a titlebar if titlebars_enabled is set to true in the rules. +client.connect_signal("request::titlebars", function(c) + -- buttons for the titlebar + local buttons = gears.table.join( + awful.button({ }, 1, function() + c:emit_signal("request::activate", "titlebar", {raise = true}) + awful.mouse.client.move(c) + end), + awful.button({ }, 3, function() + c:emit_signal("request::activate", "titlebar", {raise = true}) + awful.mouse.client.resize(c) + end) + ) + + awful.titlebar(c) : setup { + { -- Left + awful.titlebar.widget.iconwidget(c), + buttons = buttons, + layout = wibox.layout.fixed.horizontal + }, + { -- Middle + { -- Title + align = "center", + widget = awful.titlebar.widget.titlewidget(c) + }, + buttons = buttons, + layout = wibox.layout.flex.horizontal + }, + { -- Right + awful.titlebar.widget.floatingbutton (c), + awful.titlebar.widget.maximizedbutton(c), + awful.titlebar.widget.stickybutton (c), + awful.titlebar.widget.ontopbutton (c), + awful.titlebar.widget.closebutton (c), + layout = wibox.layout.fixed.horizontal() + }, + layout = wibox.layout.align.horizontal + } +end) + +-- Enable sloppy focus, so that focus follows mouse. +--[[ +client.connect_signal("mouse::enter", function(c) + c:emit_signal("request::activate", "mouse_enter", {raise = false}) +end) +]] + +client.connect_signal("focus", function(c) c.border_color = beautiful.border_focus end) +client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end) +-- }}} + + +-- autostart applets +awful.spawn.with_shell("~/.config/dwm/autostart.sh") diff --git a/.config/dwm/autostart.sh b/.config/dwm/autostart.sh new file mode 100755 index 0000000..d97e07e --- /dev/null +++ b/.config/dwm/autostart.sh @@ -0,0 +1,35 @@ +#!/bin/bash +extra=0 +if [ "$(cat /etc/hostname)" == "iceynethp1" ]; then + extra=1 +fi +if [ "$(cat /etc/hostname)" == "iceyartixmain" ]; then + extra=1 +fi + +sleep 0.1 +xset s 0 +nitrogen --restore & +if [ $extra == 1 ]; then + xrandr --dpi 90 & + xrandr --output Virtual-1 --mode 1920x1080 +fi + +xcompmgr & + +if [ $extra == 1 ]; then + if [ -z $(pgrep -f stbar.sh) ]; then + ~/stuff/scripts/system/stbar/stbar.sh & + fi + nohup pipewire & + nohup wireplumber & + nohup pipewire-pulse & +fi +if [ -z $(pgrep -f newsboat-fetch.sh) ]; then + ~/.config/dwm/newsboat-fetch.sh & +fi + +if [ -z $(pgrep wezterm) ]; then + sleep 2 + wezterm -e ~/stuff/scripts/system/task.sh +fi diff --git a/.config/dwm/newsboat-fetch.sh b/.config/dwm/newsboat-fetch.sh new file mode 100755 index 0000000..1407591 --- /dev/null +++ b/.config/dwm/newsboat-fetch.sh @@ -0,0 +1,15 @@ +#!/bin/bash +newsboat_loop(){ + newsboat -x reload + #newsboat -x print-unread | xargs -0 notify-send "newsboat feed" + + unreads=$(newsboat -x print-unread) + unreadnum=$(printf "$unreads" | sed 's/ .*//g') + + if (( $unreadnum > 0 )); then + notify-send "newsboat feed" "$unreads" + fi + sleep 2h + newsboat_loop +} +newsboat_loop diff --git a/.config/gtk-3.0/settings.ini b/.config/gtk-3.0/settings.ini new file mode 100644 index 0000000..039e625 --- /dev/null +++ b/.config/gtk-3.0/settings.ini @@ -0,0 +1,3 @@ +[Settings] +gtk-theme-name = Breeze-dark-gtk + diff --git a/.config/lf/lfrc b/.config/lf/lfrc new file mode 100644 index 0000000..c12b78d --- /dev/null +++ b/.config/lf/lfrc @@ -0,0 +1,140 @@ +# interpreter for shell commands +set shell sh + +# set '-eu' options for shell commands +# These options are used to have safer shell commands. Option '-e' is used to +# exit on error and option '-u' is used to give error for unset variables. +# Option '-f' disables pathname expansion which can be useful when $f, $fs, and +# $fx variables contain names with '*' or '?' characters. However, this option +# is used selectively within individual commands as it can be limiting at +# times. +set shellopts '-eu' + +# set internal field separator (IFS) to "\n" for shell commands +# This is useful to automatically split file names in $fs and $fx properly +# since default file separator used in these variables (i.e. 'filesep' option) +# is newline. You need to consider the values of these options and create your +# commands accordingly. +set ifs "\n" + +# leave some space at the top and the bottom of the screen +set scrolloff 10 + +# Use the `dim` attribute instead of underline for the cursor in the preview pane +set cursorpreviewfmt "\033[7;2m" + +# use enter for shell commands +map shell + +# show the result of execution of previous commands +map ` !true + +# execute current file (must be executable) +map x $$f +map X !$f + +# dedicated keys for file opener actions +map o &mimeopen $f +map O $mimeopen --ask $f + +# define a custom 'open' command +# This command is called when current file is not a directory. You may want to +# use either file extensions and/or mime types here. Below uses an editor for +# text files and a file opener for the rest. +cmd open &{{ + case $(file --mime-type -Lb $f) in + text/*) lf -remote "send $id \$$EDITOR \$fx";; + *) for f in $fx; do $OPENER $f > /dev/null 2> /dev/null & done;; + esac +}} + +# mkdir command. See wiki if you want it to select created dir +map a :push %mkdir + +# define a custom 'rename' command without prompt for overwrite +# cmd rename %[ -e $1 ] && printf "file exists" || mv $f $1 +# map r push :rename + +# make sure trash folder exists +# %mkdir -p ~/.trash + +# move current file or selected files to trash folder +# (also see 'man mv' for backup/overwrite options) +cmd trash %set -f; mv $fx ~/.trash + +# define a custom 'delete' command +# cmd delete ${{ +# set -f +# printf "$fx\n" +# printf "delete?[y/n]" +# read ans +# [ "$ans" = "y" ] && rm -rf $fx +# }} + +# use '' key for either 'trash' or 'delete' command +# map trash +# map delete + +# extract the current file with the right command +# (xkcd link: https://xkcd.com/1168/) +cmd extract ${{ + set -f + case $f in + *.tar.bz|*.tar.bz2|*.tbz|*.tbz2) tar xjvf $f;; + *.tar.gz|*.tgz) tar xzvf $f;; + *.tar.xz|*.txz) tar xJvf $f;; + *.zip) unzip $f;; + *.rar) unrar x $f;; + *.7z) 7z x $f;; + esac +}} + +# compress current file or selected files with tar and gunzip +cmd tar ${{ + set -f + mkdir $1 + cp -r $fx $1 + tar czf $1.tar.gz $1 + rm -rf $1 +}} + +# compress current file or selected files with zip +cmd zip ${{ + set -f + mkdir $1 + cp -r $fx $1 + zip -r $1.zip $1 + rm -rf $1 +}} + +cmd trash ${{ + files=$(printf "$fx" | tr '\n' ';') + while [ "$files" ]; do + file=${files%%;*} + + mv "$(basename "$file")" ~/Trash + if [ "$files" = "$file" ]; then + files='' + else + files="${files#*;}" + fi + done +}} + +cmd vim ${{ + nvim $f +}} + +cmd Sxiv ${{ + sxiv $f & disown +}} + +cmd clipf ${{ + printf "$f" | xclip -selection clipboard +}} + +map DD trash +map DP delete +map V vim +map S Sxiv +map C clipf diff --git a/.config/nvim/.luarc.json b/.config/nvim/.luarc.json new file mode 100644 index 0000000..154c5b3 --- /dev/null +++ b/.config/nvim/.luarc.json @@ -0,0 +1,13 @@ +{ + "runtime.version": "LuaJIT", + "runtime.path": [ + "lua/?.lua", + "lua/?/init.lua" + ], + "diagnostics.globals": ["vim"], + "workspace.checkThirdParty": false, + "workspace.library": [ + "$VIMRUNTIME", + "./lua" + ] +} diff --git a/.config/nvim/after/plugin/harpoon.lua b/.config/nvim/after/plugin/harpoon.lua new file mode 100644 index 0000000..c3facc9 --- /dev/null +++ b/.config/nvim/after/plugin/harpoon.lua @@ -0,0 +1,11 @@ +local mark = require("harpoon.mark") +local ui = require("harpoon.ui") + +vim.keymap.set("n","a", mark.add_file) +vim.keymap.set("n","", ui.toggle_quick_menu) + + +vim.keymap.set("n","", function() ui.nav_file(1) end) +vim.keymap.set("n","", function() ui.nav_file(2) end) +vim.keymap.set("n","", function() ui.nav_file(3) end) +vim.keymap.set("n","", function() ui.nav_file(4) end) diff --git a/.config/nvim/after/plugin/lsp.lua b/.config/nvim/after/plugin/lsp.lua new file mode 100644 index 0000000..d37197c --- /dev/null +++ b/.config/nvim/after/plugin/lsp.lua @@ -0,0 +1,45 @@ +local lsp = require("lsp-zero") + +lsp.preset("recommended") + + +local cmp = require('cmp') + +local cmp_select = {behavior = cmp.SelectBehavior.Select} +local cmp_mappings = cmp.mapping.preset.insert({ + [''] = cmp.mapping.select_prev_item(cmp_select), + [''] = cmp.mapping.select_next_item(cmp_select), + [''] = cmp.mapping.confirm({ select = true }), + [""] = cmp.mapping.complete(), +}) + +cmp.setup({ + mapping = cmp_mappings +}) + +lsp.on_attach(function(client, bufnr) + local opts = {buffer = bufnr, remap = false} + + vim.keymap.set("n", "gd", function() vim.lsp.buf.definition() end, opts) + vim.keymap.set("n", "K", function() vim.lsp.buf.hover() end, opts) + vim.keymap.set("n", "vws", function() vim.lsp.buf.workspace_symbol() end, opts) + vim.keymap.set("n", "vd", function() vim.diagnostic.open_float() end, opts) + vim.keymap.set("n", "[d", function() vim.diagnostic.goto_next() end, opts) + vim.keymap.set("n", "]d", function() vim.diagnostic.goto_prev() end, opts) + vim.keymap.set("n", "vca", function() vim.lsp.buf.code_action() end, opts) + vim.keymap.set("n", "vrr", function() vim.lsp.buf.references() end, opts) + vim.keymap.set("n", "vrn", function() vim.lsp.buf.rename() end, opts) + vim.keymap.set("i", "", function() vim.lsp.buf.signature_help() end, opts) +end) + +-- to learn how to use mason.nvim with lsp-zero +-- read this: https://github.com/VonHeikemen/lsp-zero.nvim/blob/v3.x/doc/md/guides/integrate-with-mason-nvim.md +require('mason').setup({}) +require('mason-lspconfig').setup({ + ensure_installed = {}, + handlers = { + lsp.default_setup, + }, +}) + +lsp.setup() diff --git a/.config/nvim/after/plugin/telescope.lua b/.config/nvim/after/plugin/telescope.lua new file mode 100644 index 0000000..2eae882 --- /dev/null +++ b/.config/nvim/after/plugin/telescope.lua @@ -0,0 +1,6 @@ +local builtin = require('telescope.builtin') +vim.keymap.set('n', 'pf', builtin.find_files, {}) +vim.keymap.set('n', 'ps', function() + builtin.grep_string({ search = vim.fn.input("Grep > ") }); +end) +--vim.keymap.set('n', '', builtin.git_files, {}) diff --git a/.config/nvim/after/plugin/undotree.lua b/.config/nvim/after/plugin/undotree.lua new file mode 100644 index 0000000..b6b9276 --- /dev/null +++ b/.config/nvim/after/plugin/undotree.lua @@ -0,0 +1 @@ +vim.keymap.set("n", "u", vim.cmd.UndotreeToggle) diff --git a/.config/nvim/custom-lsp/.luarc.json b/.config/nvim/custom-lsp/.luarc.json new file mode 100644 index 0000000..93e15cc --- /dev/null +++ b/.config/nvim/custom-lsp/.luarc.json @@ -0,0 +1,3 @@ +{ + "workspace.library":["~/.config/nvim/custom-lsp"] +} diff --git a/.config/nvim/init.lua b/.config/nvim/init.lua new file mode 100644 index 0000000..d3b41b0 --- /dev/null +++ b/.config/nvim/init.lua @@ -0,0 +1 @@ +require("yourmom") diff --git a/.config/nvim/lua/yourmom/init.lua b/.config/nvim/lua/yourmom/init.lua new file mode 100755 index 0000000..393115e --- /dev/null +++ b/.config/nvim/lua/yourmom/init.lua @@ -0,0 +1,39 @@ +require("yourmom.remap") + +vim.opt.guicursor="" + +vim.opt.nu = true +vim.opt.relativenumber = true + +vim.opt.tabstop = 4 +vim.opt.softtabstop = 4 +vim.opt.shiftwidth = 4 +vim.opt.expandtab = true + +vim.opt.smartindent=true + +vim.opt.wrap = false + +vim.opt.hlsearch = false +vim.opt.incsearch = true + +vim.opt.updatetime = 50 +--vim.opt.colorcolumn = "80" +--vim.cmd('colorscheme vim') +vim.cmd('colorscheme rose-pine') +vim.api.nvim_set_hl(0, "Normal", { bg = "none" }) +vim.api.nvim_set_hl(0, "NormalFloat", { bg = "none" }) + + +vim.cmd('hi SignColumn ctermbg=0') +vim.cmd('set signcolumn=no') + +vim.cmd('hi Pmenu ctermfg=120') +vim.cmd('hi Pmenu ctermbg=0') + +vim.cmd('hi StatusLine ctermfg=0') +vim.cmd('hi StatusLine ctermbg=15') +vim.cmd('hi StatusLine cterm=reverse') + +--allows highlighint in comments +--vim.api.nvim_set_hl(0, '@lsp.type.comment.cpp', {}) diff --git a/.config/nvim/lua/yourmom/packer.lua b/.config/nvim/lua/yourmom/packer.lua new file mode 100755 index 0000000..009a1d0 --- /dev/null +++ b/.config/nvim/lua/yourmom/packer.lua @@ -0,0 +1,55 @@ +-- This file can be loaded by calling `lua require('plugins')` from your init.vim + +-- Only required if you have packer configured as `opt` +vim.cmd [[packadd packer.nvim]] + +return require('packer').startup(function(use) + -- Packer can manage itself + use 'wbthomason/packer.nvim' + + use 'ThePrimeagen/vim-be-good' + use 'ThePrimeagen/harpoon' + + use { "rose-pine/neovim", as = "rose-pine" } + + use { + 'nvim-telescope/telescope.nvim', tag = '0.1.5', + -- or , branch = '0.1.x', + requires = { {'nvim-lua/plenary.nvim'} } + } + + use("mbbill/undotree") + +--[[ + use('nvim-treesitter/nvim-treesitter', {run = ':TSUpdate', + config = function() + require("nvim-treesitter.configs").setup { + ensure_installed = { "c", "lua", "rust" }, + highlight = { enable = true, } + } + end + }) + ]]-- + + use { + 'VonHeikemen/lsp-zero.nvim', + branch = 'v3.x', + requires = { + --- Uncomment the two plugins below if you want to manage the language servers from neovim + {'williamboman/mason.nvim'}, + {'williamboman/mason-lspconfig.nvim'}, + + -- LSP Support + {'neovim/nvim-lspconfig'}, + -- Autocompletion + {'hrsh7th/nvim-cmp'}, + {'hrsh7th/cmp-buffer'}, + {'hrsh7th/cmp-path'}, + {'hrsh7th/cmp-nvim-lsp'}, + {'hrsh7th/cmp-nvim-lua'}, + {'L3MON4D3/LuaSnip'}, + } + } + + +end) diff --git a/.config/nvim/lua/yourmom/remap.lua b/.config/nvim/lua/yourmom/remap.lua new file mode 100755 index 0000000..aa3a488 --- /dev/null +++ b/.config/nvim/lua/yourmom/remap.lua @@ -0,0 +1,58 @@ +vim.g.mapleader=" " +vim.keymap.set("n", "pv", vim.cmd.Ex) + + +--[[ +vim.keymap.set("n","","h") +vim.keymap.set("n","","j") +vim.keymap.set("n","","l") +vim.keymap.set("n","","k") +]]-- + + +--[[vim.cmd[[ +au VimEnter * silent! !xmodmap -e 'clear Lock' -e 'keycode 0x42 = Escape' +au VimLeave * silent! !xmodmap -e 'clear Lock' -e 'keycode 0x42 = Caps_Lock'> +]] + + +--move highlighted stuffs +vim.keymap.set("v", "J", ":m '>+1gv=gv") +vim.keymap.set("v", "K", ":m '<-2gv=gv") + +--keeps cursor at cur pos when stacking lines to single line +vim.keymap.set("n", "J", "mzJ`z") +--keeps cursur in middle with up down +vim.keymap.set("n", "", "zz") +vim.keymap.set("n", "", "zz") + +--sets leader y to put in sys clipboard +vim.keymap.set("n", "y", "\"+y") +vim.keymap.set("v", "y", "\"+y") +vim.keymap.set("n", "Y", "\"+Y") + +--nnoremap S :%s//g +vim.keymap.set("n", "S", [[:%s//]]) + +vim.keymap.set("n", "ee", "oif err != nil {}Oreturn err") + +--per file type log quick binds +local cc_command="" +local filename = vim.api.nvim_buf_get_name(0) + +if string.find(filename,".*%.js$") then + cc_command="oconsole.log();V=$hi" +elseif string.find(filename,".*%.lua$") then + cc_command="oterm.print()V=$i" +elseif string.find(filename,".*%.c$") then + cc_command="oprintf(\"debug: %i\",);V=$hi" +end + +vim.keymap.set("n", "cc", cc_command) + + +--[[ +vim.keymap("i","", function() + +end) +]] diff --git a/.config/nvim/spell/en.utf-8.add b/.config/nvim/spell/en.utf-8.add new file mode 100755 index 0000000..c85449a --- /dev/null +++ b/.config/nvim/spell/en.utf-8.add @@ -0,0 +1,21 @@ +qpwgraph +pipewire +linux +kde +wayland +VR +ish +OVR +ALVR +picom +VM +taskbar +dwm +distro +vesktop +warframe +Anthro +anthro +optifine +lol +cuda diff --git a/.config/nvim/spell/en.utf-8.add.spl b/.config/nvim/spell/en.utf-8.add.spl new file mode 100755 index 0000000000000000000000000000000000000000..1797837a5e42bad005ea8866c4ef2ebf3b4a7e7e GIT binary patch literal 253 zcmXX>F%rTc5M)nFE5|>icPuRO0SjCEn4n=o07*>rH~v%?A~WpW?%f{8<#Zl`ws!wj zN_{p}-I&h$@EE6Atiyx|Sz|=Y#ETNa6AdaTF*61hBA`^^Gxk&xYuS>b7USXQNaU5# zN+8)zbQ;`v$w~(!bx7&KLu3BS5rO%gPgJRP42%OhTo+!%m8QJw6U1B@u`I$)iEqyT QTgx7nCYM)e_|xV505dr(qW}N^ literal 0 HcmV?d00001 diff --git a/.config/picom.conf b/.config/picom.conf new file mode 100644 index 0000000..5c2cb09 --- /dev/null +++ b/.config/picom.conf @@ -0,0 +1,445 @@ +################################# +# Shadows # +################################# + + +# Enabled client-side shadows on windows. Note desktop windows +# (windows with '_NET_WM_WINDOW_TYPE_DESKTOP') never get shadow, +# unless explicitly requested using the wintypes option. +# +# shadow = false +shadow = true; + +# The blur radius for shadows, in pixels. (defaults to 12) +# shadow-radius = 12 +shadow-radius = 7; + +# The opacity of shadows. (0.0 - 1.0, defaults to 0.75) +# shadow-opacity = .75 + +# The left offset for shadows, in pixels. (defaults to -15) +# shadow-offset-x = -15 +shadow-offset-x = -7; + +# The top offset for shadows, in pixels. (defaults to -15) +# shadow-offset-y = -15 +shadow-offset-y = -7; + +# Red color value of shadow (0.0 - 1.0, defaults to 0). +# shadow-red = 0 + +# Green color value of shadow (0.0 - 1.0, defaults to 0). +# shadow-green = 0 + +# Blue color value of shadow (0.0 - 1.0, defaults to 0). +# shadow-blue = 0 + +# Hex string color value of shadow (#000000 - #FFFFFF, defaults to #000000). This option will override options set shadow-(red/green/blue) +# shadow-color = "#000000" + +# Specify a list of conditions of windows that should have no shadow. +# +# examples: +# shadow-exclude = "n:e:Notification"; +# +# shadow-exclude = [] +shadow-exclude = [ + "name = 'Notification'", + "class_g = 'Conky'", + "class_g ?= 'Notify-osd'", + "class_g = 'Cairo-clock'", + "_GTK_FRAME_EXTENTS@:c" +]; + +# Specify a list of conditions of windows that should have no shadow painted over, such as a dock window. +# clip-shadow-above = [] + +# Specify a X geometry that describes the region in which shadow should not +# be painted in, such as a dock window region. Use +# shadow-exclude-reg = "x10+0+0" +# for example, if the 10 pixels on the bottom of the screen should not have shadows painted on. +# +# shadow-exclude-reg = "" + +# Crop shadow of a window fully on a particular monitor to that monitor. This is +# currently implemented using the X RandR extension. +# crop-shadow-to-monitor = false + + +################################# +# Fading # +################################# + + +# Fade windows in/out when opening/closing and when opacity changes, +# unless no-fading-openclose is used. +# fading = false +fading = true; + +# Opacity change between steps while fading in. (0.01 - 1.0, defaults to 0.028) +# fade-in-step = 0.028 +fade-in-step = 0.03; + +# Opacity change between steps while fading out. (0.01 - 1.0, defaults to 0.03) +# fade-out-step = 0.03 +fade-out-step = 0.03; + +# The time between steps in fade step, in milliseconds. (> 0, defaults to 10) +# fade-delta = 10 + +# Specify a list of conditions of windows that should not be faded. +# fade-exclude = [] + +# Do not fade on window open/close. +# no-fading-openclose = false + +# Do not fade destroyed ARGB windows with WM frame. Workaround of bugs in Openbox, Fluxbox, etc. +# no-fading-destroyed-argb = false + + +################################# +# Transparency / Opacity # +################################# + + +# Opacity of inactive windows. (0.1 - 1.0, defaults to 1.0) +# inactive-opacity = 1 +inactive-opacity = 0.8; + +# Opacity of window titlebars and borders. (0.1 - 1.0, disabled by default) +# frame-opacity = 1.0 +frame-opacity = 0.7; + +# Let inactive opacity set by -i override the '_NET_WM_WINDOW_OPACITY' values of windows. +# inactive-opacity-override = true +inactive-opacity-override = false; + +# Default opacity for active windows. (0.0 - 1.0, defaults to 1.0) +# active-opacity = 1.0 + +# Dim inactive windows. (0.0 - 1.0, defaults to 0.0) +# inactive-dim = 0.0 + +# Specify a list of conditions of windows that should never be considered focused. +# focus-exclude = [] +focus-exclude = [ "class_g = 'Cairo-clock'" ]; + +# Use fixed inactive dim value, instead of adjusting according to window opacity. +# inactive-dim-fixed = 1.0 + +# Specify a list of opacity rules, in the format `PERCENT:PATTERN`, +# like `50:name *= "Firefox"`. picom-trans is recommended over this. +# Note we don't make any guarantee about possible conflicts with other +# programs that set '_NET_WM_WINDOW_OPACITY' on frame or client windows. +# example: +# opacity-rule = [ "80:class_g = 'URxvt'" ]; +# +# opacity-rule = [] +# + +opacity-rule = [ + "90:name *= 'Firefox'", + "95:name *= 'Discord'", + "90:name *= 'OBS'", + "90:name *= 'urxvt'", + "80:class_g = 'steam'", + "70:class_g *= 'screen-recorder-gtk'", +]; + + +################################# +# Corners # +################################# + +# Sets the radius of rounded window corners. When > 0, the compositor will +# round the corners of windows. Does not interact well with +# `transparent-clipping`. +corner-radius = 15 + +# Exclude conditions for rounded corners. +rounded-corners-exclude = [ + "window_type = 'dock'", + "window_type = 'desktop'", + "class_g = 'dmenu'", + "class_g = 'dwm'", + "class_g = 'dwmsystray'", +]; + + +################################# +# Background-Blurring # +################################# + + +# Parameters for background blurring, see the *BLUR* section for more information. +# blur-method = +# blur-size = 12 +# +# blur-deviation = false +# +# blur-strength = 5 + +# Blur background of semi-transparent / ARGB windows. +# Bad in performance, with driver-dependent behavior. +# The name of the switch may change without prior notifications. +# +# blur-background = false + +# Blur background of windows when the window frame is not opaque. +# Implies: +# blur-background +# Bad in performance, with driver-dependent behavior. The name may change. +# +# blur-background-frame = false + + +# Use fixed blur strength rather than adjusting according to window opacity. +# blur-background-fixed = false + + +# Specify the blur convolution kernel, with the following format: +# example: +# blur-kern = "5,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1"; +# +# blur-kern = "" +blur-kern = "3x3box"; + + +# Exclude conditions for background blur. +# blur-background-exclude = [] +blur-background-exclude = [ + "window_type = 'dock'", + "window_type = 'desktop'", + "_GTK_FRAME_EXTENTS@:c" +]; + +################################# +# General Settings # +################################# + +# Enable remote control via D-Bus. See the man page for more details. +# dbus = true + +# Daemonize process. Fork to background after initialization. Causes issues with certain (badly-written) drivers. +# daemon = false + +# Specify the backend to use: `xrender`, `glx`, `egl` or `xr_glx_hybrid`. +# `xrender` is the default one. +# +# backend = "glx" +backend = "xrender"; + +# Use higher precision during rendering, and apply dither when presenting the +# rendered screen. Reduces banding artifacts, but might cause performance +# degradation. Only works with OpenGL. +dithered-present = false; + +# Enable/disable VSync. +# vsync = false +vsync = false; + +# Try to detect WM windows (a non-override-redirect window with no +# child that has 'WM_STATE') and mark them as active. +# +# mark-wmwin-focused = false +mark-wmwin-focused = true; + +# Mark override-redirect windows that doesn't have a child window with 'WM_STATE' focused. +# mark-ovredir-focused = false +mark-ovredir-focused = true; + +# Try to detect windows with rounded corners and don't consider them +# shaped windows. The accuracy is not very high, unfortunately. +# +# detect-rounded-corners = false +detect-rounded-corners = true; + +# Detect '_NET_WM_WINDOW_OPACITY' on client windows, useful for window managers +# not passing '_NET_WM_WINDOW_OPACITY' of client windows to frame windows. +# +# detect-client-opacity = false +detect-client-opacity = true; + +# Use EWMH '_NET_ACTIVE_WINDOW' to determine currently focused window, +# rather than listening to 'FocusIn'/'FocusOut' event. Might have more accuracy, +# provided that the WM supports it. +# +# use-ewmh-active-win = false + +# Unredirect all windows if a full-screen opaque window is detected, +# to maximize performance for full-screen windows. Known to cause flickering +# when redirecting/unredirecting windows. +# +# unredir-if-possible = false + +# Delay before unredirecting the window, in milliseconds. Defaults to 0. +# unredir-if-possible-delay = 0 + +# Conditions of windows that shouldn't be considered full-screen for unredirecting screen. +# unredir-if-possible-exclude = [] + +# Use 'WM_TRANSIENT_FOR' to group windows, and consider windows +# in the same group focused at the same time. +# +# detect-transient = false +detect-transient = true; + +# Use 'WM_CLIENT_LEADER' to group windows, and consider windows in the same +# group focused at the same time. This usually means windows from the same application +# will be considered focused or unfocused at the same time. +# 'WM_TRANSIENT_FOR' has higher priority if detect-transient is enabled, too. +# +# detect-client-leader = false + +# Resize damaged region by a specific number of pixels. +# A positive value enlarges it while a negative one shrinks it. +# If the value is positive, those additional pixels will not be actually painted +# to screen, only used in blur calculation, and such. (Due to technical limitations, +# with use-damage, those pixels will still be incorrectly painted to screen.) +# Primarily used to fix the line corruption issues of blur, +# in which case you should use the blur radius value here +# (e.g. with a 3x3 kernel, you should use `--resize-damage 1`, +# with a 5x5 one you use `--resize-damage 2`, and so on). +# May or may not work with *--glx-no-stencil*. Shrinking doesn't function correctly. +# +# resize-damage = 1 + +# Specify a list of conditions of windows that should be painted with inverted color. +# Resource-hogging, and is not well tested. +# +# invert-color-include = [] + +# GLX backend: Avoid using stencil buffer, useful if you don't have a stencil buffer. +# Might cause incorrect opacity when rendering transparent content (but never +# practically happened) and may not work with blur-background. +# My tests show a 15% performance boost. Recommended. +# +# glx-no-stencil = false + +# GLX backend: Avoid rebinding pixmap on window damage. +# Probably could improve performance on rapid window content changes, +# but is known to break things on some drivers (LLVMpipe, xf86-video-intel, etc.). +# Recommended if it works. +# +# glx-no-rebind-pixmap = false + +# Disable the use of damage information. +# This cause the whole screen to be redrawn every time, instead of the part of the screen +# has actually changed. Potentially degrades the performance, but might fix some artifacts. +# The opposing option is use-damage +# +# no-use-damage = false +use-damage = true; + +# Use X Sync fence to sync clients' draw calls, to make sure all draw +# calls are finished before picom starts drawing. Needed on nvidia-drivers +# with GLX backend for some users. +# +# xrender-sync-fence = false +xrender-sync-fence = true + +# GLX backend: Use specified GLSL fragment shader for rendering window +# contents. Read the man page for a detailed explanation of the interface. +# +# window-shader-fg = "default" + +# Use rules to set per-window shaders. Syntax is SHADER_PATH:PATTERN, similar +# to opacity-rule. SHADER_PATH can be "default". This overrides window-shader-fg. +# +# window-shader-fg-rule = [ +# "my_shader.frag:window_type != 'dock'" +# ] + +# Force all windows to be painted with blending. Useful if you +# have a glx-fshader-win that could turn opaque pixels transparent. +# +# force-win-blend = false + +# Do not use EWMH to detect fullscreen windows. +# Reverts to checking if a window is fullscreen based only on its size and coordinates. +# +# no-ewmh-fullscreen = false + +# Dimming bright windows so their brightness doesn't exceed this set value. +# Brightness of a window is estimated by averaging all pixels in the window, +# so this could comes with a performance hit. +# Setting this to 1.0 disables this behaviour. Requires --use-damage to be disabled. (default: 1.0) +# +# max-brightness = 1.0 + +# Make transparent windows clip other windows like non-transparent windows do, +# instead of blending on top of them. +# +# transparent-clipping = false + +# Specify a list of conditions of windows that should never have transparent +# clipping applied. Useful for screenshot tools, where you need to be able to +# see through transparent parts of the window. +# +# transparent-clipping-exclude = [] + +# Set the log level. Possible values are: +# "trace", "debug", "info", "warn", "error" +# in increasing level of importance. Case doesn't matter. +# If using the "TRACE" log level, it's better to log into a file +# using *--log-file*, since it can generate a huge stream of logs. +# +# log-level = "debug" +log-level = "warn"; + +# Set the log file. +# If *--log-file* is never specified, logs will be written to stderr. +# Otherwise, logs will to written to the given file, though some of the early +# logs might still be written to the stderr. +# When setting this option from the config file, it is recommended to use an absolute path. +# +# log-file = "/path/to/your/log/file" + +# Show all X errors (for debugging) +# show-all-xerrors = false + +# Write process ID to a file. +# write-pid-path = "/path/to/your/log/file" + +# Window type settings +# +# 'WINDOW_TYPE' is one of the 15 window types defined in EWMH standard: +# "unknown", "desktop", "dock", "toolbar", "menu", "utility", +# "splash", "dialog", "normal", "dropdown_menu", "popup_menu", +# "tooltip", "notification", "combo", and "dnd". +# +# Following per window-type options are available: :: +# +# fade, shadow::: +# Controls window-type-specific shadow and fade settings. +# +# opacity::: +# Controls default opacity of the window type. +# +# focus::: +# Controls whether the window of this type is to be always considered focused. +# (By default, all window types except "normal" and "dialog" has this on.) +# +# full-shadow::: +# Controls whether shadow is drawn under the parts of the window that you +# normally won't be able to see. Useful when the window has parts of it +# transparent, and you want shadows in those areas. +# +# clip-shadow-above::: +# Controls whether shadows that would have been drawn above the window should +# be clipped. Useful for dock windows that should have no shadow painted on top. +# +# redir-ignore::: +# Controls whether this type of windows should cause screen to become +# redirected again after been unredirected. If you have unredir-if-possible +# set, and doesn't want certain window to cause unnecessary screen redirection, +# you can set this to `true`. +# +wintypes: +{ + tooltip = { fade = true; shadow = true; opacity = 0.75; focus = true; full-shadow = false; }; + dock = { shadow = false; clip-shadow-above = true; } + dnd = { shadow = false; } + popup_menu = { opacity = 0.8; } + dropdown_menu = { opacity = 0.8; } +}; diff --git a/.config/rofi/config.rasi b/.config/rofi/config.rasi new file mode 100644 index 0000000..5191111 --- /dev/null +++ b/.config/rofi/config.rasi @@ -0,0 +1,5 @@ +@theme "Arc-Dark" + +*{ + background: #30303050; +} diff --git a/.config/screenkey.json b/.config/screenkey.json new file mode 100644 index 0000000..4e01f42 --- /dev/null +++ b/.config/screenkey.json @@ -0,0 +1,32 @@ +{ + "no_systray": false, + "timeout": 2.5, + "recent_thr": 0.1, + "compr_cnt": 3, + "ignore": [], + "position": "fixed", + "persist": false, + "window": null, + "font_desc": "Inconsolata Light 10", + "font_size": "small", + "font_color": "white", + "bg_color": "#114400f423d6", + "opacity": 0.1, + "key_mode": "translated", + "bak_mode": "baked", + "mods_mode": "normal", + "mods_only": false, + "multiline": false, + "vis_shift": false, + "vis_space": true, + "geometry": [ + 1303, + 180, + 611, + 103 + ], + "screen": 0, + "start_disabled": false, + "mouse": false, + "button_hide_duration": 0.5 +} \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..3fe919b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule ".config/nvim/custom-lsp/lua-ls-cc-tweaked"] + path = .config/nvim/custom-lsp/lua-ls-cc-tweaked + url = https://github.com/nvim-computercraft/lua-ls-cc-tweaked.git diff --git a/.gtkrc-2.0 b/.gtkrc-2.0 new file mode 100644 index 0000000..92e5350 --- /dev/null +++ b/.gtkrc-2.0 @@ -0,0 +1,13 @@ +gtk-enable-event-sounds=1 +gtk-enable-animations=1 +gtk-theme-name="Breeze-Dark" +gtk-primary-button-warps-slider=1 +gtk-toolbar-style=3 +gtk-menu-images=1 +gtk-button-images=1 +gtk-cursor-theme-size=24 +gtk-cursor-theme-name="breeze_cursors" +gtk-sound-theme-name="freedesktop" +gtk-icon-theme-name="breeze-dark" +gtk-font-name="Noto Sans, 10" + diff --git a/.profile b/.profile new file mode 100755 index 0000000..788fc7f --- /dev/null +++ b/.profile @@ -0,0 +1,93 @@ +#!/bin/bash +if test -z "${XDG_RUNTIME_DIR}"; then + export XDG_RUNTIME_DIR=/tmp/${UID}-runtime-dir + if ! test -d "${XDG_RUNTIME_DIR}"; then + mkdir "${XDG_RUNTIME_DIR}" + chmod 0700 "${XDG_RUNTIME_DIR}" + fi +fi + +#if [ -z "${WAYLAND_DISPLAY}" ] && [ "${XDG_VTNR}" -eq 1 ]; then +# exec sway > ~/.swaylog 2>&1 +#fi + +# . torsocks on +export PROMPT_EOL_MARK="" +export EDITOR="nvim" +export BROWSER="firefox" +export PREFIX=/usr +export PATH="$PATH:$HOME/stuff/scripts/system:$HOME/.cargo/bin:$HOME/stuff/scripts/system/backup" +export MANPAGER='nvim +Man!' +# export DWM_NOTIF_FILE="/home/iceyrazor/stuff/scripts/c/SDL/notif/notif.txt" + +export heartost="/home/iceyrazor/.steam/root/steamapps/music/Heartbound - OST" + +export cutil=/home/iceyrazor/stuff/scripts/c/my_utils + +alias ls='ls --color=auto' +alias lss="sudo du -ah -d 1 | sort -hr" +alias lsu="lsblk --filter 'NAME=~\"sd[abcde]\"' -o NAME,MOUNTPOINTS" +alias lsblkfs="lsblk -o PATH,FSTYPE,MOUNTPOINT" +alias grep='grep --color=auto' +alias fastfetch='fastfetch --localip-show-ipv4 0' + +alias ascii="~/stuff/scripts/c/SDL/ascii/ascii" + +alias watchlss="sudo watch \"du -ah -d 1 | sort -hr\"" +alias lfub=~/.local/bin/lf-gadgets/lf-ueberzug/lf-ueberzug +alias lfk=~/.local/bin/lf-gadgets/lf-kitty/lf-kitty +alias ovim=/usr/bin/vim +alias vim=nvim +alias fzf="fzf --walker-skip=.private-parent" +alias fcd="cd \"\$(fzf --walker dir,hidden --walker-skip=.private-parent)\"" +alias ts="~/stuff/scripts/system/tmux-sessionizer.sh" + + +#alias updateL='sudo /home/iceyrazor/update_list/update_list.sh ' +alias session="./Downloads/session-desktop-linux-x86_64-1.12.4.AppImage > /dev/null & disown" +alias simplex="_JAVA_AWT_WM_NONREPARENTING=1 ./Downloads/simplex-desktop-x86_64.AppImage > /dev/null & disown" +alias loki="./stuff/scripts/loki-toggle.sh" +alias lokig="sudo Lokinet-GUI.AppImage --no-sandbox > /dev/null & disown" +alias alvr="WINIT_X11_SCALE_FACTOR=\"1\" ~/stuff/app_images/ALVR-x86_64.AppImage & disown" +alias wlx="~/stuff/app_images/WlxOverlay-v1.4.5-x86_64.AppImage & disown" +alias obss="sudo obs && obs & disown" + +alias killa="~/stuff/killall.sh" +alias bbackup="~/stuff/scripts/system/backup/backup.sh" +alias bbacklap="~/stuff/scripts/system/backup/backup-tol.sh" +alias bgit="~/stuff/scripts/system/backup/move-to-git.sh" +alias vasm="~/stuff/manual-programs/vasm/vasm6502_oldstyle -Fbin -dotdir " +alias pipes="pipes.sh -t 0 -p 3 -f 30 -r 2000" + +alias bri="sudo ~/stuff/scripts/system/bri.sh" + +# mounting +alias umsu="sudo umount u" +alias umsu2="sudo umount u2" +alias mswin="sudo mount -o umask=0,uid=nobody,gid=nobody /dev/sdb3 ~/windir" +alias umswin="sudo umount ~/windir" +alias msbak="sudo cryptsetup open /dev/sda1 backups && sudo mount /dev/mapper/backups ~/mnt-backups" # && sudo bindfs -u iceyrazor /mnt-backups ~/mnt-backups" +alias umsbak="sudo umount ~/mnt-backups && sudo cryptsetup close backups" # " sudo umount /mnt-backups && sudo cryptsetup close backups" +alias msfd="sudo mount /dev/sdc1 u2" +alias msf="sudo cryptsetup open /dev/sdc2 flashdrive && sudo mount /dev/mapper/flashdrive ~/u" +alias umsf="sudo umount ~/u && sudo cryptsetup close flashdrive" + +alias cam="ffplay -input_format mjpeg -fast -fflags +nobuffer -i -framerate 30 -max_delay 100 -max_probe_packets 0 -analyzeduration 0 -flags +low_delay /dev/video0" +alias sc="ffmpeg -f x11grab -framerate 1 -video_size 1920x1200 -i :0.0 -vframes 1 -crf 18 ~/output.jpeg" +alias sc2="escrotum -s ~/Pictures/%Y-%m-%d-%H%M%S_$wx$h_escrotum.png" +alias scs="sleep 3s && ffmpeg -f x11grab -framerate 1 -video_size 1920x1200 -i :0.0 -vframes 1 -crf 18 output.jpeg" +alias wwrite="watch -d grep -e Dirty: -e Writeback: /proc/meminfo" +alias gol="~/stuff/scripts/c/SDL/game-of-life/game-of-life & disown" + + +alias statst="echo full_stat:true > ~/stuff/scripts/system/stbar/config.txt" +alias statsf="echo full_stat:false > ~/stuff/scripts/system/stbar/config.txt" + +alias get_drm="sudo cat /sys/module/nvidia_drm/parameters/modeset" + +alias nodem="find . -name 'node_modules' -type d | xargs du -sh | sort -hr | fzf -m --header \"select witch ones to delete\" --preview 'cat $(dirname {})/package.json'|awk print '{print $2}' | xargs -r rm -rf" + +alias walltaker="stuff/manual-programs/git/walltaker-client/walltaker.sh" +alias savewall="stuff/manual-programs/git/walltaker-client/save.sh" + +xset r rate 300 50 diff --git a/.surf/styles/default.css b/.surf/styles/default.css new file mode 100644 index 0000000..69259cc --- /dev/null +++ b/.surf/styles/default.css @@ -0,0 +1,16 @@ +*,div,pre,textarea,body,input,td,tr,p { + background-color: #202020 !important; + background-image: none !important; + color: #bbbbbb !important; +} +h1,h2,h3,h4 { + background-color: #202020 !important; + color: #b8ddea !important; +} +img { + opacity: .5; +} +img:hover { + opacity: 1; +} + diff --git a/.urlview b/.urlview new file mode 100755 index 0000000..19a0946 --- /dev/null +++ b/.urlview @@ -0,0 +1,29 @@ +############################################################################### +# Urlview configuration file. +# man urlview +# +# Put this file in: $HOME/.urlview +# Put url_handler.sh in: /usr/bin +# +# You can call 'urlview' while in 'mutt' by pressing the Ctrl b keys. +# Put these macros in your $HOME/.muttrc file. +# +# macro index \cb |urlview\n +# macro pager \cb |urlview\n +# +# You can call 'urlview' while in 'tin' by pressing | then a for article, +# put urlview as the pipe command. +# +# Regular expression to use to match URLs. + +#REGEXP (((http|https|ftp|gopher)|mailto):(//)?[^ >"\t]*|www\.[-a-z0-9.]+)[^ .,;\t>">\):] +REGEXP (((http|https|ftp|gopher)|mailto)[.:][^ >"\t]*|www\.[-a-z0-9.]+)[^ .,;\t>">\):] + +# Command to invoke for selected URL. Use lynx, netscape, or url_handler.sh +# shell script. Alternatively, you can leave COMMAND unset and set the BROWSER +# environment variable instead. + +#COMMAND lynx %s +#COMMAND netscape -remote 'openURL(%s)' +#COMMAND url_handler.sh +COMMAND ~/stuff/scripts/system/url-handler.sh diff --git a/.vimrc b/.vimrc new file mode 100755 index 0000000..720d670 --- /dev/null +++ b/.vimrc @@ -0,0 +1,78 @@ +" set bg=light + +" ignores case in search +set ic + +"Disable compatibility with vi which can cause unexpected issues. +set nocompatible + +" set to system clipboard +set clipboard=unnamedplus + +" Enable type file detection. Vim will be able to try to detect the type of file in use. +filetype on + +" Enable plugins and load plugin for the detected file type. +filetype plugin on + +" Load an indent file for the detected file type. +filetype indent on + +" Add numbers to each line on the left-hand side. +set number relativenumber + +" Turn syntax highlighting on. +syntax on + +" Enable auto completion menu after pressing TAB. +set wildmenu + +" Make wildmenu behave like similar to Bash completion. +"set wildmode=list:longest +set wildmode=longest,list,full + +" There are certain files that we would never want to edit with Vim. +" Wildmenu will ignore files with these extensions. +set wildignore=*.docx,*.jpg,*.png,*.gif,*.pdf,*.pyc,*.exe,*.flv,*.img,*.xlsx + +" set wrap enable +set wrap + +" set tab size +set tabstop=4 +set softtabstop=4 +set shiftwidth=4 + +set encoding=utf-8 + +" split open at the bottem and right +set splitbelow splitright +" easier nav +map h +map j +map k +map l + + +" supposed to map urlview. doesnt fucking work. figures +" :noremap u :wsilent !urlview + +nnoremap S :%s//g + +nnoremap :tabnew + +" au VimEnter * silent! !xmodmap -e 'clear Lock' -e 'keycode 0x42 = Escape' +au VimLeave * silent! !xmodmap -e 'clear Lock' -e 'keycode 0x42 = Caps_Lock'> + +map +vnoremap "+y +map "+P + +" add vimrc.plug +if filereadable(expand("~.vimrc.plug")) + source ~/.vimrc.plug +endif + + +" auto delete trailing whitespace on save +autocmd BufWritePre * %s/\s\+$//e diff --git a/.wezterm.lua b/.wezterm.lua new file mode 100755 index 0000000..3e4242d --- /dev/null +++ b/.wezterm.lua @@ -0,0 +1,50 @@ +local wezterm = require 'wezterm' +local config = {} +local act = wezterm.action + +--config.font = wezterm.font 'Classic Console' +--config.font_size = 15 +--config.font = wezterm.font 'Source Code Pro' +config.font = wezterm.font 'CozetteVector' +config.font_size = 15 + +config.keys = { + { key = 'h', mods = 'SHIFT|CTRL', action = act.ActivatePaneDirection 'Left' }, + { key = 'h', mods = 'SHIFT|ALT|CTRL', action = act.AdjustPaneSize{ 'Left', 1 } }, + { key = 'l', mods = 'SHIFT|CTRL', action = act.ActivatePaneDirection 'Right' }, + { key = 'l', mods = 'SHIFT|ALT|CTRL', action = act.AdjustPaneSize{ 'Right', 1 } }, + { key = 'k', mods = 'SHIFT|CTRL', action = act.ActivatePaneDirection 'Up' }, + { key = 'k', mods = 'SHIFT|ALT|CTRL', action = act.AdjustPaneSize{ 'Up', 1 } }, + { key = 'j', mods = 'SHIFT|CTRL', action = act.ActivatePaneDirection 'Down' }, + { key = 'j', mods = 'SHIFT|ALT|CTRL', action = act.AdjustPaneSize{ 'Down', 1 } }, +} + +config.colors={ + foreground = '#e6e6e6', + background = '#101010', + cursor_fg = '#fabd2f', + ansi = { + '#263640', + '#d12f2c', + '#819400', + '#b08500', + '#2587cc', + '#696ebf', + '#289c93', + '#bfbaac', + }, + brights = { + '#4a697d', + '#fa3935', + '#a4bd00', + '#d9a400', + '#09a2f5', + '#8086e8', + '#00c5ba', + '#fdf6e3', + }, +} + +config.window_background_opacity = 0.8 + +return config diff --git a/.zshrc b/.zshrc new file mode 100755 index 0000000..9e07903 --- /dev/null +++ b/.zshrc @@ -0,0 +1,22 @@ +# Lines configured by zsh-newuser-install +HISTFILE=~/.histfile +HISTSIZE=1000 +SAVEHIST=1000 +bindkey -v +# End of lines configured by zsh-newuser-install + +PS1='%B%F{white}[%B%F{red}Z%B%F{magenta}%n%B%F{yellow}@%B%F{magenta}%M %B%F{cyan}%1~%B%F{white}]%B%F{default}$ ' +#PS1='%B%F{white}[%B%F{red}Z%B%F{magenta}ARCH %B%F{cyan}%1~%B%F{white}]%B%F{default}$ ' + + +# Yank to the system clipboard +function vi-yank-xclip { + #zle vi-yank + echo "$CUTBUFFER" | xclip -selection clipboard +} + +zle -N vi-yank-xclip +bindkey -M vicmd ' y' vi-yank-xclip + +source ~/stuff/scripts/system/neoboot.sh +source ~/.profile diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..115d8fa --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 iceyrazor + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..e3d6d27 --- /dev/null +++ b/README.md @@ -0,0 +1,65 @@ +# hi +this is just some configs and stuffs i decided to put on my github + +# requirements +- for dwm or awesome + - xorg-server + - xorg-xinit + - xorg-xrandr + - xorg-xsetroot + - libxft + - libxinerama +- for awesome extra + - rofi +- for surf + - gcr + - webkit2gtk + - optional + - gst-plugins-base + - gst-plugins-good + - gst-libav + - gstreamer +- installing dwm, dmenu, and surf + - cd into respective directory + - sudo make clean install + - startx +- for neovim + - packer +- for urlview - urlview +- terminal + - primary wezterm + - secondary rxvt-unicode less memory usage +- font - ttf-inconsolata +- login + - lightdm + - lightdm-gtk-greeter +- theme + - breeze-dark-gtk - manual download. put in usr/share/themes +- for qt to gtk theme + - qt6gtk2 + - qt5-styleplugins +- background setter - nitrogen +- file manager + - lf + - pcmanfm +- shell + - zsh +- audio + - pipewire-alsa + - pipewire-jack + - pipewire-pulse + - qpwgraph +- onscreen keys - screenkey +- compositor - picom +- inetutils - for normal ftp +- escrotum-git for screenshots +- tor stuff + - tor + - torsocks + - nyx + - tor-browser +- notifications + - libnotify + - notify-send +- calender + - calcurse diff --git a/stuff/manual-programs/suckless/dmenu-5.2/LICENSE b/stuff/manual-programs/suckless/dmenu-5.2/LICENSE new file mode 100644 index 0000000..2a64b28 --- /dev/null +++ b/stuff/manual-programs/suckless/dmenu-5.2/LICENSE @@ -0,0 +1,30 @@ +MIT/X Consortium License + +© 2006-2019 Anselm R Garbe +© 2006-2008 Sander van Dijk +© 2006-2007 Michał Janeczek +© 2007 Kris Maglione +© 2009 Gottox +© 2009 Markus Schnalke +© 2009 Evan Gates +© 2010-2012 Connor Lane Smith +© 2014-2022 Hiltjo Posthuma +© 2015-2019 Quentin Rameau + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/stuff/manual-programs/suckless/dmenu-5.2/Makefile b/stuff/manual-programs/suckless/dmenu-5.2/Makefile new file mode 100644 index 0000000..a03a95c --- /dev/null +++ b/stuff/manual-programs/suckless/dmenu-5.2/Makefile @@ -0,0 +1,64 @@ +# dmenu - dynamic menu +# See LICENSE file for copyright and license details. + +include config.mk + +SRC = drw.c dmenu.c stest.c util.c +OBJ = $(SRC:.c=.o) + +all: options dmenu stest + +options: + @echo dmenu build options: + @echo "CFLAGS = $(CFLAGS)" + @echo "LDFLAGS = $(LDFLAGS)" + @echo "CC = $(CC)" + +.c.o: + $(CC) -c $(CFLAGS) $< + +config.h: + cp config.def.h $@ + +$(OBJ): arg.h config.h config.mk drw.h + +dmenu: dmenu.o drw.o util.o + $(CC) -o $@ dmenu.o drw.o util.o $(LDFLAGS) + +stest: stest.o + $(CC) -o $@ stest.o $(LDFLAGS) + +clean: + rm -f dmenu stest $(OBJ) dmenu-$(VERSION).tar.gz + +dist: clean + mkdir -p dmenu-$(VERSION) + cp LICENSE Makefile README arg.h config.def.h config.mk dmenu.1\ + drw.h util.h dmenu_path dmenu_run stest.1 $(SRC)\ + dmenu-$(VERSION) + tar -cf dmenu-$(VERSION).tar dmenu-$(VERSION) + gzip dmenu-$(VERSION).tar + rm -rf dmenu-$(VERSION) + +install: all + mkdir -p $(DESTDIR)$(PREFIX)/bin + cp -f dmenu dmenu_path dmenu_run stest $(DESTDIR)$(PREFIX)/bin + chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu + chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu_path + chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu_run + chmod 755 $(DESTDIR)$(PREFIX)/bin/stest + mkdir -p $(DESTDIR)$(MANPREFIX)/man1 + sed "s/VERSION/$(VERSION)/g" < dmenu.1 > $(DESTDIR)$(MANPREFIX)/man1/dmenu.1 + sed "s/VERSION/$(VERSION)/g" < stest.1 > $(DESTDIR)$(MANPREFIX)/man1/stest.1 + chmod 644 $(DESTDIR)$(MANPREFIX)/man1/dmenu.1 + chmod 644 $(DESTDIR)$(MANPREFIX)/man1/stest.1 + +uninstall: + rm -f $(DESTDIR)$(PREFIX)/bin/dmenu\ + $(DESTDIR)$(PREFIX)/bin/dmenu_path\ + $(DESTDIR)$(PREFIX)/bin/dmenu_run\ + $(DESTDIR)$(PREFIX)/bin/stest\ + $(DESTDIR)$(MANPREFIX)/man1/dmenu.1\ + $(DESTDIR)$(MANPREFIX)/man1/stest.1 + +.PHONY: all options clean dist install uninstall diff --git a/stuff/manual-programs/suckless/dmenu-5.2/README b/stuff/manual-programs/suckless/dmenu-5.2/README new file mode 100644 index 0000000..a8fcdfe --- /dev/null +++ b/stuff/manual-programs/suckless/dmenu-5.2/README @@ -0,0 +1,24 @@ +dmenu - dynamic menu +==================== +dmenu is an efficient dynamic menu for X. + + +Requirements +------------ +In order to build dmenu you need the Xlib header files. + + +Installation +------------ +Edit config.mk to match your local setup (dmenu is installed into +the /usr/local namespace by default). + +Afterwards enter the following command to build and install dmenu +(if necessary as root): + + make clean install + + +Running dmenu +------------- +See the man page for details. diff --git a/stuff/manual-programs/suckless/dmenu-5.2/arg.h b/stuff/manual-programs/suckless/dmenu-5.2/arg.h new file mode 100644 index 0000000..e94e02b --- /dev/null +++ b/stuff/manual-programs/suckless/dmenu-5.2/arg.h @@ -0,0 +1,49 @@ +/* + * Copy me if you can. + * by 20h + */ + +#ifndef ARG_H__ +#define ARG_H__ + +extern char *argv0; + +/* use main(int argc, char *argv[]) */ +#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ + argv[0] && argv[0][0] == '-'\ + && argv[0][1];\ + argc--, argv++) {\ + char argc_;\ + char **argv_;\ + int brk_;\ + if (argv[0][1] == '-' && argv[0][2] == '\0') {\ + argv++;\ + argc--;\ + break;\ + }\ + for (brk_ = 0, argv[0]++, argv_ = argv;\ + argv[0][0] && !brk_;\ + argv[0]++) {\ + if (argv_ != argv)\ + break;\ + argc_ = argv[0][0];\ + switch (argc_) + +#define ARGEND }\ + } + +#define ARGC() argc_ + +#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\ + ((x), abort(), (char *)0) :\ + (brk_ = 1, (argv[0][1] != '\0')?\ + (&argv[0][1]) :\ + (argc--, argv++, argv[0]))) + +#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\ + (char *)0 :\ + (brk_ = 1, (argv[0][1] != '\0')?\ + (&argv[0][1]) :\ + (argc--, argv++, argv[0]))) + +#endif diff --git a/stuff/manual-programs/suckless/dmenu-5.2/config.h b/stuff/manual-programs/suckless/dmenu-5.2/config.h new file mode 100644 index 0000000..ad70a45 --- /dev/null +++ b/stuff/manual-programs/suckless/dmenu-5.2/config.h @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +/* Default settings; can be overriden by command line. */ + +static int topbar = 0; /* -b option; if 0, dmenu appears at bottom */ +/* -fn option overrides fonts[0]; default X11 font or font set */ +static const char *fonts[] = { + "monospace:size=10" +}; +static const char *prompt = NULL; /* -p option; prompt to the left of input field */ +static const char *colors[SchemeLast][2] = { + /* fg bg */ + [SchemeNorm] = { "#bbbbbb", "#222222" }, + [SchemeSel] = { "#eeeeee", "#005577" }, + [SchemeOut] = { "#000000", "#00ffff" }, +}; +/* -l option; if nonzero, dmenu uses vertical list with given number of lines */ +static unsigned int lines = 0; + +/* + * Characters not considered part of a word while deleting words + * for example: " /?\"&[]" + */ +static const char worddelimiters[] = " "; diff --git a/stuff/manual-programs/suckless/dmenu-5.2/config.mk b/stuff/manual-programs/suckless/dmenu-5.2/config.mk new file mode 100644 index 0000000..566348b --- /dev/null +++ b/stuff/manual-programs/suckless/dmenu-5.2/config.mk @@ -0,0 +1,32 @@ +# dmenu version +VERSION = 5.2 + +# paths +PREFIX = /usr/local +MANPREFIX = $(PREFIX)/share/man + +X11INC = /usr/X11R6/include +X11LIB = /usr/X11R6/lib + +# Xinerama, comment if you don't want it +XINERAMALIBS = -lXinerama +XINERAMAFLAGS = -DXINERAMA + +# freetype +FREETYPELIBS = -lfontconfig -lXft +FREETYPEINC = /usr/include/freetype2 +# OpenBSD (uncomment) +#FREETYPEINC = $(X11INC)/freetype2 +#MANPREFIX = ${PREFIX}/man + +# includes and libs +INCS = -I$(X11INC) -I$(FREETYPEINC) +LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) + +# flags +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS) +CFLAGS = -std=c99 -pedantic -Wall -Os $(INCS) $(CPPFLAGS) +LDFLAGS = $(LIBS) + +# compiler and linker +CC = cc diff --git a/stuff/manual-programs/suckless/dmenu-5.2/dmenu b/stuff/manual-programs/suckless/dmenu-5.2/dmenu new file mode 100644 index 0000000000000000000000000000000000000000..0b4106fe4815745ebe8f19b34ae3333b88817c5d GIT binary patch literal 42664 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 literal 0 HcmV?d00001 diff --git a/stuff/manual-programs/suckless/dmenu-5.2/dmenu.1 b/stuff/manual-programs/suckless/dmenu-5.2/dmenu.1 new file mode 100644 index 0000000..323f93c --- /dev/null +++ b/stuff/manual-programs/suckless/dmenu-5.2/dmenu.1 @@ -0,0 +1,194 @@ +.TH DMENU 1 dmenu\-VERSION +.SH NAME +dmenu \- dynamic menu +.SH SYNOPSIS +.B dmenu +.RB [ \-bfiv ] +.RB [ \-l +.IR lines ] +.RB [ \-m +.IR monitor ] +.RB [ \-p +.IR prompt ] +.RB [ \-fn +.IR font ] +.RB [ \-nb +.IR color ] +.RB [ \-nf +.IR color ] +.RB [ \-sb +.IR color ] +.RB [ \-sf +.IR color ] +.RB [ \-w +.IR windowid ] +.P +.BR dmenu_run " ..." +.SH DESCRIPTION +.B dmenu +is a dynamic menu for X, which reads a list of newline\-separated items from +stdin. When the user selects an item and presses Return, their choice is printed +to stdout and dmenu terminates. Entering text will narrow the items to those +matching the tokens in the input. +.P +.B dmenu_run +is a script used by +.IR dwm (1) +which lists programs in the user's $PATH and runs the result in their $SHELL. +.SH OPTIONS +.TP +.B \-b +dmenu appears at the bottom of the screen. +.TP +.B \-f +dmenu grabs the keyboard before reading stdin if not reading from a tty. This +is faster, but will lock up X until stdin reaches end\-of\-file. +.TP +.B \-i +dmenu matches menu items case insensitively. +.TP +.BI \-l " lines" +dmenu lists items vertically, with the given number of lines. +.TP +.BI \-m " monitor" +dmenu is displayed on the monitor number supplied. Monitor numbers are starting +from 0. +.TP +.BI \-p " prompt" +defines the prompt to be displayed to the left of the input field. +.TP +.BI \-fn " font" +defines the font or font set used. +.TP +.BI \-nb " color" +defines the normal background color. +.IR #RGB , +.IR #RRGGBB , +and X color names are supported. +.TP +.BI \-nf " color" +defines the normal foreground color. +.TP +.BI \-sb " color" +defines the selected background color. +.TP +.BI \-sf " color" +defines the selected foreground color. +.TP +.B \-v +prints version information to stdout, then exits. +.TP +.BI \-w " windowid" +embed into windowid. +.SH USAGE +dmenu is completely controlled by the keyboard. Items are selected using the +arrow keys, page up, page down, home, and end. +.TP +.B Tab +Copy the selected item to the input field. +.TP +.B Return +Confirm selection. Prints the selected item to stdout and exits, returning +success. +.TP +.B Ctrl-Return +Confirm selection. Prints the selected item to stdout and continues. +.TP +.B Shift\-Return +Confirm input. Prints the input text to stdout and exits, returning success. +.TP +.B Escape +Exit without selecting an item, returning failure. +.TP +.B Ctrl-Left +Move cursor to the start of the current word +.TP +.B Ctrl-Right +Move cursor to the end of the current word +.TP +.B C\-a +Home +.TP +.B C\-b +Left +.TP +.B C\-c +Escape +.TP +.B C\-d +Delete +.TP +.B C\-e +End +.TP +.B C\-f +Right +.TP +.B C\-g +Escape +.TP +.B C\-h +Backspace +.TP +.B C\-i +Tab +.TP +.B C\-j +Return +.TP +.B C\-J +Shift-Return +.TP +.B C\-k +Delete line right +.TP +.B C\-m +Return +.TP +.B C\-M +Shift-Return +.TP +.B C\-n +Down +.TP +.B C\-p +Up +.TP +.B C\-u +Delete line left +.TP +.B C\-w +Delete word left +.TP +.B C\-y +Paste from primary X selection +.TP +.B C\-Y +Paste from X clipboard +.TP +.B M\-b +Move cursor to the start of the current word +.TP +.B M\-f +Move cursor to the end of the current word +.TP +.B M\-g +Home +.TP +.B M\-G +End +.TP +.B M\-h +Up +.TP +.B M\-j +Page down +.TP +.B M\-k +Page up +.TP +.B M\-l +Down +.SH SEE ALSO +.IR dwm (1), +.IR stest (1) diff --git a/stuff/manual-programs/suckless/dmenu-5.2/dmenu.c b/stuff/manual-programs/suckless/dmenu-5.2/dmenu.c new file mode 100644 index 0000000..7cf253b --- /dev/null +++ b/stuff/manual-programs/suckless/dmenu-5.2/dmenu.c @@ -0,0 +1,791 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#ifdef XINERAMA +#include +#endif +#include + +#include "drw.h" +#include "util.h" + +/* macros */ +#define INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \ + * MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org))) +#define LENGTH(X) (sizeof X / sizeof X[0]) +#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) + +/* enums */ +enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */ + +struct item { + char *text; + struct item *left, *right; + int out; +}; + +static char text[BUFSIZ] = ""; +static char *embed; +static int bh, mw, mh; +static int inputw = 0, promptw; +static int lrpad; /* sum of left and right padding */ +static size_t cursor; +static struct item *items = NULL; +static struct item *matches, *matchend; +static struct item *prev, *curr, *next, *sel; +static int mon = -1, screen; + +static Atom clip, utf8; +static Display *dpy; +static Window root, parentwin, win; +static XIC xic; + +static Drw *drw; +static Clr *scheme[SchemeLast]; + +#include "config.h" + +static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; +static char *(*fstrstr)(const char *, const char *) = strstr; + +static unsigned int +textw_clamp(const char *str, unsigned int n) +{ + unsigned int w = drw_fontset_getwidth_clamp(drw, str, n) + lrpad; + return MIN(w, n); +} + +static void +appenditem(struct item *item, struct item **list, struct item **last) +{ + if (*last) + (*last)->right = item; + else + *list = item; + + item->left = *last; + item->right = NULL; + *last = item; +} + +static void +calcoffsets(void) +{ + int i, n; + + if (lines > 0) + n = lines * bh; + else + n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">")); + /* calculate which items will begin the next page and previous page */ + for (i = 0, next = curr; next; next = next->right) + if ((i += (lines > 0) ? bh : textw_clamp(next->text, n)) > n) + break; + for (i = 0, prev = curr; prev && prev->left; prev = prev->left) + if ((i += (lines > 0) ? bh : textw_clamp(prev->left->text, n)) > n) + break; +} + +static void +cleanup(void) +{ + size_t i; + + XUngrabKey(dpy, AnyKey, AnyModifier, root); + for (i = 0; i < SchemeLast; i++) + free(scheme[i]); + for (i = 0; items && items[i].text; ++i) + free(items[i].text); + free(items); + drw_free(drw); + XSync(dpy, False); + XCloseDisplay(dpy); +} + +static char * +cistrstr(const char *h, const char *n) +{ + size_t i; + + if (!n[0]) + return (char *)h; + + for (; *h; ++h) { + for (i = 0; n[i] && tolower((unsigned char)n[i]) == + tolower((unsigned char)h[i]); ++i) + ; + if (n[i] == '\0') + return (char *)h; + } + return NULL; +} + +static int +drawitem(struct item *item, int x, int y, int w) +{ + if (item == sel) + drw_setscheme(drw, scheme[SchemeSel]); + else if (item->out) + drw_setscheme(drw, scheme[SchemeOut]); + else + drw_setscheme(drw, scheme[SchemeNorm]); + + return drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0); +} + +static void +drawmenu(void) +{ + unsigned int curpos; + struct item *item; + int x = 0, y = 0, w; + + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, 0, 0, mw, mh, 1, 1); + + if (prompt && *prompt) { + drw_setscheme(drw, scheme[SchemeSel]); + x = drw_text(drw, x, 0, promptw, bh, lrpad / 2, prompt, 0); + } + /* draw input field */ + w = (lines > 0 || !matches) ? mw - x : inputw; + drw_setscheme(drw, scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0); + + curpos = TEXTW(text) - TEXTW(&text[cursor]); + if ((curpos += lrpad / 2 - 1) < w) { + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0); + } + + if (lines > 0) { + /* draw vertical list */ + for (item = curr; item != next; item = item->right) + drawitem(item, x, y += bh, mw - x); + } else if (matches) { + /* draw horizontal list */ + x += inputw; + w = TEXTW("<"); + if (curr->left) { + drw_setscheme(drw, scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, "<", 0); + } + x += w; + for (item = curr; item != next; item = item->right) + x = drawitem(item, x, 0, textw_clamp(item->text, mw - x - TEXTW(">"))); + if (next) { + w = TEXTW(">"); + drw_setscheme(drw, scheme[SchemeNorm]); + drw_text(drw, mw - w, 0, w, bh, lrpad / 2, ">", 0); + } + } + drw_map(drw, win, 0, 0, mw, mh); +} + +static void +grabfocus(void) +{ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; + Window focuswin; + int i, revertwin; + + for (i = 0; i < 100; ++i) { + XGetInputFocus(dpy, &focuswin, &revertwin); + if (focuswin == win) + return; + XSetInputFocus(dpy, win, RevertToParent, CurrentTime); + nanosleep(&ts, NULL); + } + die("cannot grab focus"); +} + +static void +grabkeyboard(void) +{ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 }; + int i; + + if (embed) + return; + /* try to grab keyboard, we may have to wait for another process to ungrab */ + for (i = 0; i < 1000; i++) { + if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync, + GrabModeAsync, CurrentTime) == GrabSuccess) + return; + nanosleep(&ts, NULL); + } + die("cannot grab keyboard"); +} + +static void +match(void) +{ + static char **tokv = NULL; + static int tokn = 0; + + char buf[sizeof text], *s; + int i, tokc = 0; + size_t len, textsize; + struct item *item, *lprefix, *lsubstr, *prefixend, *substrend; + + strcpy(buf, text); + /* separate input text into tokens to be matched individually */ + for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " ")) + if (++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv))) + die("cannot realloc %zu bytes:", tokn * sizeof *tokv); + len = tokc ? strlen(tokv[0]) : 0; + + matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL; + textsize = strlen(text) + 1; + for (item = items; item && item->text; item++) { + for (i = 0; i < tokc; i++) + if (!fstrstr(item->text, tokv[i])) + break; + if (i != tokc) /* not all tokens match */ + continue; + /* exact matches go first, then prefixes, then substrings */ + if (!tokc || !fstrncmp(text, item->text, textsize)) + appenditem(item, &matches, &matchend); + else if (!fstrncmp(tokv[0], item->text, len)) + appenditem(item, &lprefix, &prefixend); + else + appenditem(item, &lsubstr, &substrend); + } + if (lprefix) { + if (matches) { + matchend->right = lprefix; + lprefix->left = matchend; + } else + matches = lprefix; + matchend = prefixend; + } + if (lsubstr) { + if (matches) { + matchend->right = lsubstr; + lsubstr->left = matchend; + } else + matches = lsubstr; + matchend = substrend; + } + curr = sel = matches; + calcoffsets(); +} + +static void +insert(const char *str, ssize_t n) +{ + if (strlen(text) + n > sizeof text - 1) + return; + /* move existing text out of the way, insert new text, and update cursor */ + memmove(&text[cursor + n], &text[cursor], sizeof text - cursor - MAX(n, 0)); + if (n > 0) + memcpy(&text[cursor], str, n); + cursor += n; + match(); +} + +static size_t +nextrune(int inc) +{ + ssize_t n; + + /* return location of next utf8 rune in the given direction (+1 or -1) */ + for (n = cursor + inc; n + inc >= 0 && (text[n] & 0xc0) == 0x80; n += inc) + ; + return n; +} + +static void +movewordedge(int dir) +{ + if (dir < 0) { /* move cursor to the start of the word*/ + while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)])) + cursor = nextrune(-1); + while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)])) + cursor = nextrune(-1); + } else { /* move cursor to the end of the word */ + while (text[cursor] && strchr(worddelimiters, text[cursor])) + cursor = nextrune(+1); + while (text[cursor] && !strchr(worddelimiters, text[cursor])) + cursor = nextrune(+1); + } +} + +static void +keypress(XKeyEvent *ev) +{ + char buf[32]; + int len; + KeySym ksym; + Status status; + + len = XmbLookupString(xic, ev, buf, sizeof buf, &ksym, &status); + switch (status) { + default: /* XLookupNone, XBufferOverflow */ + return; + case XLookupChars: + goto insert; + case XLookupKeySym: + case XLookupBoth: + break; + } + + if (ev->state & ControlMask) { + switch(ksym) { + case XK_a: ksym = XK_Home; break; + case XK_b: ksym = XK_Left; break; + case XK_c: ksym = XK_Escape; break; + case XK_d: ksym = XK_Delete; break; + case XK_e: ksym = XK_End; break; + case XK_f: ksym = XK_Right; break; + case XK_g: ksym = XK_Escape; break; + case XK_h: ksym = XK_BackSpace; break; + case XK_i: ksym = XK_Tab; break; + case XK_j: /* fallthrough */ + case XK_J: /* fallthrough */ + case XK_m: /* fallthrough */ + case XK_M: ksym = XK_Return; ev->state &= ~ControlMask; break; + case XK_n: ksym = XK_Down; break; + case XK_p: ksym = XK_Up; break; + + case XK_k: /* delete right */ + text[cursor] = '\0'; + match(); + break; + case XK_u: /* delete left */ + insert(NULL, 0 - cursor); + break; + case XK_w: /* delete word */ + while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)])) + insert(NULL, nextrune(-1) - cursor); + while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)])) + insert(NULL, nextrune(-1) - cursor); + break; + case XK_y: /* paste selection */ + case XK_Y: + XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY, + utf8, utf8, win, CurrentTime); + return; + case XK_Left: + case XK_KP_Left: + movewordedge(-1); + goto draw; + case XK_Right: + case XK_KP_Right: + movewordedge(+1); + goto draw; + case XK_Return: + case XK_KP_Enter: + break; + case XK_bracketleft: + cleanup(); + exit(1); + default: + return; + } + } else if (ev->state & Mod1Mask) { + switch(ksym) { + case XK_b: + movewordedge(-1); + goto draw; + case XK_f: + movewordedge(+1); + goto draw; + case XK_g: ksym = XK_Home; break; + case XK_G: ksym = XK_End; break; + case XK_h: ksym = XK_Up; break; + case XK_j: ksym = XK_Next; break; + case XK_k: ksym = XK_Prior; break; + case XK_l: ksym = XK_Down; break; + default: + return; + } + } + + switch(ksym) { + default: +insert: + if (!iscntrl((unsigned char)*buf)) + insert(buf, len); + break; + case XK_Delete: + case XK_KP_Delete: + if (text[cursor] == '\0') + return; + cursor = nextrune(+1); + /* fallthrough */ + case XK_BackSpace: + if (cursor == 0) + return; + insert(NULL, nextrune(-1) - cursor); + break; + case XK_End: + case XK_KP_End: + if (text[cursor] != '\0') { + cursor = strlen(text); + break; + } + if (next) { + /* jump to end of list and position items in reverse */ + curr = matchend; + calcoffsets(); + curr = prev; + calcoffsets(); + while (next && (curr = curr->right)) + calcoffsets(); + } + sel = matchend; + break; + case XK_Escape: + cleanup(); + exit(1); + case XK_Home: + case XK_KP_Home: + if (sel == matches) { + cursor = 0; + break; + } + sel = curr = matches; + calcoffsets(); + break; + case XK_Left: + case XK_KP_Left: + if (cursor > 0 && (!sel || !sel->left || lines > 0)) { + cursor = nextrune(-1); + break; + } + if (lines > 0) + return; + /* fallthrough */ + case XK_Up: + case XK_KP_Up: + if (sel && sel->left && (sel = sel->left)->right == curr) { + curr = prev; + calcoffsets(); + } + break; + case XK_Next: + case XK_KP_Next: + if (!next) + return; + sel = curr = next; + calcoffsets(); + break; + case XK_Prior: + case XK_KP_Prior: + if (!prev) + return; + sel = curr = prev; + calcoffsets(); + break; + case XK_Return: + case XK_KP_Enter: + puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); + if (!(ev->state & ControlMask)) { + cleanup(); + exit(0); + } + if (sel) + sel->out = 1; + break; + case XK_Right: + case XK_KP_Right: + if (text[cursor] != '\0') { + cursor = nextrune(+1); + break; + } + if (lines > 0) + return; + /* fallthrough */ + case XK_Down: + case XK_KP_Down: + if (sel && sel->right && (sel = sel->right) == next) { + curr = next; + calcoffsets(); + } + break; + case XK_Tab: + if (!sel) + return; + cursor = strnlen(sel->text, sizeof text - 1); + memcpy(text, sel->text, cursor); + text[cursor] = '\0'; + match(); + break; + } + +draw: + drawmenu(); +} + +static void +paste(void) +{ + char *p, *q; + int di; + unsigned long dl; + Atom da; + + /* we have been given the current selection, now insert it into input */ + if (XGetWindowProperty(dpy, win, utf8, 0, (sizeof text / 4) + 1, False, + utf8, &da, &di, &dl, &dl, (unsigned char **)&p) + == Success && p) { + insert(p, (q = strchr(p, '\n')) ? q - p : (ssize_t)strlen(p)); + XFree(p); + } + drawmenu(); +} + +static void +readstdin(void) +{ + char *line = NULL; + size_t i, junk, size = 0; + ssize_t len; + + /* read each line from stdin and add it to the item list */ + for (i = 0; (len = getline(&line, &junk, stdin)) != -1; i++, line = NULL) { + if (i + 1 >= size / sizeof *items) + if (!(items = realloc(items, (size += BUFSIZ)))) + die("cannot realloc %zu bytes:", size); + if (line[len - 1] == '\n') + line[len - 1] = '\0'; + items[i].text = line; + items[i].out = 0; + } + if (items) + items[i].text = NULL; + lines = MIN(lines, i); +} + +static void +run(void) +{ + XEvent ev; + + while (!XNextEvent(dpy, &ev)) { + if (XFilterEvent(&ev, win)) + continue; + switch(ev.type) { + case DestroyNotify: + if (ev.xdestroywindow.window != win) + break; + cleanup(); + exit(1); + case Expose: + if (ev.xexpose.count == 0) + drw_map(drw, win, 0, 0, mw, mh); + break; + case FocusIn: + /* regrab focus from parent window */ + if (ev.xfocus.window != win) + grabfocus(); + break; + case KeyPress: + keypress(&ev.xkey); + break; + case SelectionNotify: + if (ev.xselection.property == utf8) + paste(); + break; + case VisibilityNotify: + if (ev.xvisibility.state != VisibilityUnobscured) + XRaiseWindow(dpy, win); + break; + } + } +} + +static void +setup(void) +{ + int x, y, i, j; + unsigned int du; + XSetWindowAttributes swa; + XIM xim; + Window w, dw, *dws; + XWindowAttributes wa; + XClassHint ch = {"dmenu", "dmenu"}; +#ifdef XINERAMA + XineramaScreenInfo *info; + Window pw; + int a, di, n, area = 0; +#endif + /* init appearance */ + for (j = 0; j < SchemeLast; j++) + scheme[j] = drw_scm_create(drw, colors[j], 2); + + clip = XInternAtom(dpy, "CLIPBOARD", False); + utf8 = XInternAtom(dpy, "UTF8_STRING", False); + + /* calculate menu geometry */ + bh = drw->fonts->h + 2; + lines = MAX(lines, 0); + mh = (lines + 1) * bh; +#ifdef XINERAMA + i = 0; + if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) { + XGetInputFocus(dpy, &w, &di); + if (mon >= 0 && mon < n) + i = mon; + else if (w != root && w != PointerRoot && w != None) { + /* find top-level window containing current input focus */ + do { + if (XQueryTree(dpy, (pw = w), &dw, &w, &dws, &du) && dws) + XFree(dws); + } while (w != root && w != pw); + /* find xinerama screen with which the window intersects most */ + if (XGetWindowAttributes(dpy, pw, &wa)) + for (j = 0; j < n; j++) + if ((a = INTERSECT(wa.x, wa.y, wa.width, wa.height, info[j])) > area) { + area = a; + i = j; + } + } + /* no focused window is on screen, so use pointer location instead */ + if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du)) + for (i = 0; i < n; i++) + if (INTERSECT(x, y, 1, 1, info[i]) != 0) + break; + + x = info[i].x_org; + y = info[i].y_org + (topbar ? 0 : info[i].height - mh); + mw = info[i].width; + XFree(info); + } else +#endif + { + if (!XGetWindowAttributes(dpy, parentwin, &wa)) + die("could not get embedding window attributes: 0x%lx", + parentwin); + x = 0; + y = topbar ? 0 : wa.height - mh; + mw = wa.width; + } + promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; + inputw = mw / 3; /* input width: ~33% of monitor width */ + match(); + + /* create menu window */ + swa.override_redirect = True; + swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; + swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; + win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0, + CopyFromParent, CopyFromParent, CopyFromParent, + CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); + XSetClassHint(dpy, win, &ch); + + + /* input methods */ + if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL) + die("XOpenIM failed: could not open input device"); + + xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, win, XNFocusWindow, win, NULL); + + XMapRaised(dpy, win); + if (embed) { + XSelectInput(dpy, parentwin, FocusChangeMask | SubstructureNotifyMask); + if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) { + for (i = 0; i < du && dws[i] != win; ++i) + XSelectInput(dpy, dws[i], FocusChangeMask); + XFree(dws); + } + grabfocus(); + } + drw_resize(drw, mw, mh); + drawmenu(); +} + +static void +usage(void) +{ + die("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" + " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]"); +} + +int +main(int argc, char *argv[]) +{ + XWindowAttributes wa; + int i, fast = 0; + + for (i = 1; i < argc; i++) + /* these options take no arguments */ + if (!strcmp(argv[i], "-v")) { /* prints version information */ + puts("dmenu-"VERSION); + exit(0); + } else if (!strcmp(argv[i], "-b")) /* appears at the bottom of the screen */ + topbar = 0; + else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */ + fast = 1; + else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */ + fstrncmp = strncasecmp; + fstrstr = cistrstr; + } else if (i + 1 == argc) + usage(); + /* these options take one argument */ + else if (!strcmp(argv[i], "-l")) /* number of lines in vertical list */ + lines = atoi(argv[++i]); + else if (!strcmp(argv[i], "-m")) + mon = atoi(argv[++i]); + else if (!strcmp(argv[i], "-p")) /* adds prompt to left of input field */ + prompt = argv[++i]; + else if (!strcmp(argv[i], "-fn")) /* font or font set */ + fonts[0] = argv[++i]; + else if (!strcmp(argv[i], "-nb")) /* normal background color */ + colors[SchemeNorm][ColBg] = argv[++i]; + else if (!strcmp(argv[i], "-nf")) /* normal foreground color */ + colors[SchemeNorm][ColFg] = argv[++i]; + else if (!strcmp(argv[i], "-sb")) /* selected background color */ + colors[SchemeSel][ColBg] = argv[++i]; + else if (!strcmp(argv[i], "-sf")) /* selected foreground color */ + colors[SchemeSel][ColFg] = argv[++i]; + else if (!strcmp(argv[i], "-w")) /* embedding window id */ + embed = argv[++i]; + else + usage(); + + if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) + fputs("warning: no locale support\n", stderr); + if (!(dpy = XOpenDisplay(NULL))) + die("cannot open display"); + screen = DefaultScreen(dpy); + root = RootWindow(dpy, screen); + if (!embed || !(parentwin = strtol(embed, NULL, 0))) + parentwin = root; + if (!XGetWindowAttributes(dpy, parentwin, &wa)) + die("could not get embedding window attributes: 0x%lx", + parentwin); + drw = drw_create(dpy, screen, root, wa.width, wa.height); + if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) + die("no fonts could be loaded."); + lrpad = drw->fonts->h; + +#ifdef __OpenBSD__ + if (pledge("stdio rpath", NULL) == -1) + die("pledge"); +#endif + + if (fast && !isatty(0)) { + grabkeyboard(); + readstdin(); + } else { + readstdin(); + grabkeyboard(); + } + setup(); + run(); + + return 1; /* unreachable */ +} diff --git a/stuff/manual-programs/suckless/dmenu-5.2/dmenu.o b/stuff/manual-programs/suckless/dmenu-5.2/dmenu.o new file mode 100644 index 0000000000000000000000000000000000000000..3a5ebea187945a8568c2061e58628bfcd9d033ac GIT binary patch literal 31672 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 +#include +#include +#include +#include + +#include "drw.h" +#include "util.h" + +#define UTF_INVALID 0xFFFD +#define UTF_SIZ 4 + +static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; +static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; +static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; +static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; + +static long +utf8decodebyte(const char c, size_t *i) +{ + for (*i = 0; *i < (UTF_SIZ + 1); ++(*i)) + if (((unsigned char)c & utfmask[*i]) == utfbyte[*i]) + return (unsigned char)c & ~utfmask[*i]; + return 0; +} + +static size_t +utf8validate(long *u, size_t i) +{ + if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) + *u = UTF_INVALID; + for (i = 1; *u > utfmax[i]; ++i) + ; + return i; +} + +static size_t +utf8decode(const char *c, long *u, size_t clen) +{ + size_t i, j, len, type; + long udecoded; + + *u = UTF_INVALID; + if (!clen) + return 0; + udecoded = utf8decodebyte(c[0], &len); + if (!BETWEEN(len, 1, UTF_SIZ)) + return 1; + for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { + udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); + if (type) + return j; + } + if (j < len) + return 0; + *u = udecoded; + utf8validate(u, len); + + return len; +} + +Drw * +drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h) +{ + Drw *drw = ecalloc(1, sizeof(Drw)); + + drw->dpy = dpy; + drw->screen = screen; + drw->root = root; + drw->w = w; + drw->h = h; + drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); + drw->gc = XCreateGC(dpy, root, 0, NULL); + XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); + + return drw; +} + +void +drw_resize(Drw *drw, unsigned int w, unsigned int h) +{ + if (!drw) + return; + + drw->w = w; + drw->h = h; + if (drw->drawable) + XFreePixmap(drw->dpy, drw->drawable); + drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen)); +} + +void +drw_free(Drw *drw) +{ + XFreePixmap(drw->dpy, drw->drawable); + XFreeGC(drw->dpy, drw->gc); + drw_fontset_free(drw->fonts); + free(drw); +} + +/* This function is an implementation detail. Library users should use + * drw_fontset_create instead. + */ +static Fnt * +xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) +{ + Fnt *font; + XftFont *xfont = NULL; + FcPattern *pattern = NULL; + + if (fontname) { + /* Using the pattern found at font->xfont->pattern does not yield the + * same substitution results as using the pattern returned by + * FcNameParse; using the latter results in the desired fallback + * behaviour whereas the former just results in missing-character + * rectangles being drawn, at least with some fonts. */ + if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) { + fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname); + return NULL; + } + if (!(pattern = FcNameParse((FcChar8 *) fontname))) { + fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname); + XftFontClose(drw->dpy, xfont); + return NULL; + } + } else if (fontpattern) { + if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) { + fprintf(stderr, "error, cannot load font from pattern.\n"); + return NULL; + } + } else { + die("no font specified."); + } + + font = ecalloc(1, sizeof(Fnt)); + font->xfont = xfont; + font->pattern = pattern; + font->h = xfont->ascent + xfont->descent; + font->dpy = drw->dpy; + + return font; +} + +static void +xfont_free(Fnt *font) +{ + if (!font) + return; + if (font->pattern) + FcPatternDestroy(font->pattern); + XftFontClose(font->dpy, font->xfont); + free(font); +} + +Fnt* +drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount) +{ + Fnt *cur, *ret = NULL; + size_t i; + + if (!drw || !fonts) + return NULL; + + for (i = 1; i <= fontcount; i++) { + if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) { + cur->next = ret; + ret = cur; + } + } + return (drw->fonts = ret); +} + +void +drw_fontset_free(Fnt *font) +{ + if (font) { + drw_fontset_free(font->next); + xfont_free(font); + } +} + +void +drw_clr_create(Drw *drw, Clr *dest, const char *clrname) +{ + if (!drw || !dest || !clrname) + return; + + if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen), + DefaultColormap(drw->dpy, drw->screen), + clrname, dest)) + die("error, cannot allocate color '%s'", clrname); +} + +/* Wrapper to create color schemes. The caller has to call free(3) on the + * returned color scheme when done using it. */ +Clr * +drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) +{ + size_t i; + Clr *ret; + + /* need at least two colors for a scheme */ + if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor)))) + return NULL; + + for (i = 0; i < clrcount; i++) + drw_clr_create(drw, &ret[i], clrnames[i]); + return ret; +} + +void +drw_setfontset(Drw *drw, Fnt *set) +{ + if (drw) + drw->fonts = set; +} + +void +drw_setscheme(Drw *drw, Clr *scm) +{ + if (drw) + drw->scheme = scm; +} + +void +drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert) +{ + if (!drw || !drw->scheme) + return; + XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel); + if (filled) + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); + else + XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1); +} + +int +drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert) +{ + int i, ty, ellipsis_x = 0; + unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len; + XftDraw *d = NULL; + Fnt *usedfont, *curfont, *nextfont; + int utf8strlen, utf8charlen, render = x || y || w || h; + long utf8codepoint = 0; + const char *utf8str; + FcCharSet *fccharset; + FcPattern *fcpattern; + FcPattern *match; + XftResult result; + int charexists = 0, overflow = 0; + /* keep track of a couple codepoints for which we have no match. */ + enum { nomatches_len = 64 }; + static struct { long codepoint[nomatches_len]; unsigned int idx; } nomatches; + static unsigned int ellipsis_width = 0; + + if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts) + return 0; + + if (!render) { + w = invert ? invert : ~invert; + } else { + XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); + d = XftDrawCreate(drw->dpy, drw->drawable, + DefaultVisual(drw->dpy, drw->screen), + DefaultColormap(drw->dpy, drw->screen)); + x += lpad; + w -= lpad; + } + + usedfont = drw->fonts; + if (!ellipsis_width && render) + ellipsis_width = drw_fontset_getwidth(drw, "..."); + while (1) { + ew = ellipsis_len = utf8strlen = 0; + utf8str = text; + nextfont = NULL; + while (*text) { + utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); + for (curfont = drw->fonts; curfont; curfont = curfont->next) { + charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); + if (charexists) { + drw_font_getexts(curfont, text, utf8charlen, &tmpw, NULL); + if (ew + ellipsis_width <= w) { + /* keep track where the ellipsis still fits */ + ellipsis_x = x + ew; + ellipsis_w = w - ew; + ellipsis_len = utf8strlen; + } + + if (ew + tmpw > w) { + overflow = 1; + /* called from drw_fontset_getwidth_clamp(): + * it wants the width AFTER the overflow + */ + if (!render) + x += tmpw; + else + utf8strlen = ellipsis_len; + } else if (curfont == usedfont) { + utf8strlen += utf8charlen; + text += utf8charlen; + ew += tmpw; + } else { + nextfont = curfont; + } + break; + } + } + + if (overflow || !charexists || nextfont) + break; + else + charexists = 0; + } + + if (utf8strlen) { + if (render) { + ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; + XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], + usedfont->xfont, x, ty, (XftChar8 *)utf8str, utf8strlen); + } + x += ew; + w -= ew; + } + if (render && overflow) + drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert); + + if (!*text || overflow) { + break; + } else if (nextfont) { + charexists = 0; + usedfont = nextfont; + } else { + /* Regardless of whether or not a fallback font is found, the + * character must be drawn. */ + charexists = 1; + + for (i = 0; i < nomatches_len; ++i) { + /* avoid calling XftFontMatch if we know we won't find a match */ + if (utf8codepoint == nomatches.codepoint[i]) + goto no_match; + } + + fccharset = FcCharSetCreate(); + FcCharSetAddChar(fccharset, utf8codepoint); + + if (!drw->fonts->pattern) { + /* Refer to the comment in xfont_create for more information. */ + die("the first font in the cache must be loaded from a font string."); + } + + fcpattern = FcPatternDuplicate(drw->fonts->pattern); + FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); + FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); + + FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); + FcDefaultSubstitute(fcpattern); + match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result); + + FcCharSetDestroy(fccharset); + FcPatternDestroy(fcpattern); + + if (match) { + usedfont = xfont_create(drw, NULL, match); + if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) { + for (curfont = drw->fonts; curfont->next; curfont = curfont->next) + ; /* NOP */ + curfont->next = usedfont; + } else { + xfont_free(usedfont); + nomatches.codepoint[++nomatches.idx % nomatches_len] = utf8codepoint; +no_match: + usedfont = drw->fonts; + } + } + } + } + if (d) + XftDrawDestroy(d); + + return x + (render ? w : 0); +} + +void +drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) +{ + if (!drw) + return; + + XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y); + XSync(drw->dpy, False); +} + +unsigned int +drw_fontset_getwidth(Drw *drw, const char *text) +{ + if (!drw || !drw->fonts || !text) + return 0; + return drw_text(drw, 0, 0, 0, 0, 0, text, 0); +} + +unsigned int +drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n) +{ + unsigned int tmp = 0; + if (drw && drw->fonts && text && n) + tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n); + return MIN(n, tmp); +} + +void +drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h) +{ + XGlyphInfo ext; + + if (!font || !text) + return; + + XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext); + if (w) + *w = ext.xOff; + if (h) + *h = font->h; +} + +Cur * +drw_cur_create(Drw *drw, int shape) +{ + Cur *cur; + + if (!drw || !(cur = ecalloc(1, sizeof(Cur)))) + return NULL; + + cur->cursor = XCreateFontCursor(drw->dpy, shape); + + return cur; +} + +void +drw_cur_free(Drw *drw, Cur *cursor) +{ + if (!cursor) + return; + + XFreeCursor(drw->dpy, cursor->cursor); + free(cursor); +} diff --git a/stuff/manual-programs/suckless/dmenu-5.2/drw.h b/stuff/manual-programs/suckless/dmenu-5.2/drw.h new file mode 100644 index 0000000..fd7631b --- /dev/null +++ b/stuff/manual-programs/suckless/dmenu-5.2/drw.h @@ -0,0 +1,58 @@ +/* See LICENSE file for copyright and license details. */ + +typedef struct { + Cursor cursor; +} Cur; + +typedef struct Fnt { + Display *dpy; + unsigned int h; + XftFont *xfont; + FcPattern *pattern; + struct Fnt *next; +} Fnt; + +enum { ColFg, ColBg }; /* Clr scheme index */ +typedef XftColor Clr; + +typedef struct { + unsigned int w, h; + Display *dpy; + int screen; + Window root; + Drawable drawable; + GC gc; + Clr *scheme; + Fnt *fonts; +} Drw; + +/* Drawable abstraction */ +Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h); +void drw_resize(Drw *drw, unsigned int w, unsigned int h); +void drw_free(Drw *drw); + +/* Fnt abstraction */ +Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount); +void drw_fontset_free(Fnt* set); +unsigned int drw_fontset_getwidth(Drw *drw, const char *text); +unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n); +void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h); + +/* Colorscheme abstraction */ +void drw_clr_create(Drw *drw, Clr *dest, const char *clrname); +Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount); + +/* Cursor abstraction */ +Cur *drw_cur_create(Drw *drw, int shape); +void drw_cur_free(Drw *drw, Cur *cursor); + +/* Drawing context manipulation */ +void drw_setfontset(Drw *drw, Fnt *set); +void drw_setscheme(Drw *drw, Clr *scm); + +/* Drawing functions */ +void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert); +int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert); + +/* Map functions */ +void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); diff --git a/stuff/manual-programs/suckless/dmenu-5.2/drw.o b/stuff/manual-programs/suckless/dmenu-5.2/drw.o new file mode 100644 index 0000000000000000000000000000000000000000..249df4c15338687c02fcb827f26766f348397455 GIT binary patch literal 11000 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 literal 0 HcmV?d00001 diff --git a/stuff/manual-programs/suckless/dmenu-5.2/stest b/stuff/manual-programs/suckless/dmenu-5.2/stest new file mode 100644 index 0000000000000000000000000000000000000000..592d3a07de8a848f2c6a5497f23f85532b8551cc GIT binary patch literal 16432 zcmeHOeQaCTb-$!6OZ5jS$9AeFal>ZvqO27y*|IAqV@%5Wc+BM3i|xiq>^##VDY21B zg?zN-EKZbC3d$&S)vh02m!L|pZpF|Q-kJr)3S{)`*sBp>b_aCE1~l%Fw&c{tYCb$C zY0dr4efQ9hFJ%ANfC0mJf%ncmzw>eLJNMrAL7w|$|ImQb;SgLJ#NC3p$(1JJSAr8g zssiE{Jz_b|9~W!HV(^P3X3G60fz&J)ot3m%;SHc<*GiQt^cE8qOu2_d$*xxMFEJ%d zMT^OkT_aT$Z>R6lg`hBHdAU806boUa6QqE`)M`gAXFH@=%=#+nRTUSH>=b0GUj&og zoU)r!c1%5NrzpphVnRocil?3WA*14#XCdr%6Uxp``;gauP>?+;<8hDd4rcEZDapK7nxIEyqzu7>`p8u&;J ze5MBexf=Mt*1)&d!1vd{zg+|W;~Mym8aU0G72;!J&W{QTulsMJPI%r==yhD^!Cl+* za3mQSiKUE4a@V%4V~KcVSLnc4MCkg+!9-k78KI=1>!xZ|#Z-Je8H*cHF$P^jq>OMZ zF2>VFN{mO6$wU&KAQ*l`A0B-~kA`AnBASduL}Vgnh~cqBDiV$*#Yn`!+M`yn7Kc@< z2Se}#e{dtBsu5iuo(SpDSUfZqdn^KJa(FZ;l95oD+$6>$aiXE&;Ycba;A>A;7cJyX zvW^y#p@Sg;x(J9S;>K_y9*vEZp*>N)v({gYq*t=C<@7>TX%GC|!>UD6vcOyj? zs~?AXHfzK+NX&`#OkAU)q)+R4kywMp!}qb5zW7xv??!RE!oDl{MPj|;SH)t>>2Bgv zeEO!?N2uLF@KpHu!{a|rHy@PaK9e%;QTU|45@$ZY#l-1e<20-C{Err#A88~wZ^4@^ z`WG!YI$AE5EVz0Fk+M0zsY1T#zQ!f*H*197$RJU_$xxdr1QKYr;Odbl@fHhiy}!0v zaCv`~+PFtqaE={`+AX+x6(Lx3TJWV3F;6`fe3=FJTW}0)xo8&LRYrx_VZq%Ne2)d^ zxkTdq7JLN(s*L*03dPNOza6*WYKoYO^>aM}^$64>P>;a>$q2md{`mV^<`>P{Oygg# z6GEHL8_v>sEpxh=-jszXZ9E6KwDvWe-M9KtBYu=b#Y-iWwf{goJz|UJCI5HCJBiOr z{%?qy7u^!P5$O8)D_)1$UHDfurEPmiPGxa6N9o*ucy{gVG2 z@$?E&+#&hLh^I$y(J%QV@$|?oc1r%U#M7g;=#l&Z;^`4vY?1tf#M7g-D8L8q4}2!D zdnnhjvP+1-uD;wzX}6Y(H}BM*`b9e)s9|kp(b{%sYuTx`Rsdc3uDq7*Yip)ci#D@Z z%QhZ{OKs*TqFZuLIT5SLEgkOZ_h9wRpkpfUo_Z72-|tA@F!`iYq?c)#SDOQ+*NPX( zZRu<WA*HoXjjZrcS!2z5{7+^JVw+H&N+xzw%ZfH}Iv*Rmb7s$tN8m z?F!E5&D!+8rI!}Ih|$n;x?{cxUW1vl&022bpP@^W@5j?ks9*I`_g@cW-V7CfeXUg5 zHhg6|@BVV${c?V5w(oC6y6Jl~zVn?>DtsRb^OyUwSG1hZfiM;B0YKB{IN5jQVZ8M$ zjL0H59_F03S_ z8DggMPu!yA`kG3UJxkIJXP_hD?6tz{Xk`9O;rMURr6(xBh38QXW?!ZL=tJ4dk_VH% zg_!dYs@NLaGrlo|Ko~vqXSCd&l|yK^Rh!v{@e5`z4rSkZgsU&QZ3z3yA5;GE*)y8uMX zHJ&4~`KqxROZVC*QO7lZq;$!B>m=!&QWW|xNd1jpCvwL%ExVwdd~=I-@@j+TIHO&- zW~_pPSCxb2(xs^T*1qfZ)W1pJ^RN}^4ZF3B??q^0w*1ssuFd%F23}e{3#c%R&Yo#B z066xYy58SY(d%`(e~`c82y}PAd<%6cxAF0%v}`Z|wu3Kx_SdD--_!l0aN>hfY4=Vo z`vKNk52B2<_9?a2zTMUiK+C?X<&3uG!T@Y=`AuE<;u+u>U$}!hym<1c@EZS-@jXDS z(K6H5=2Yb&)}5 z(S@HECvb6=h9)s3ro+H8zMtdrgt7EWU)v`Zxu@uEmGS)xVQIMgnH2WVcWJqo+KvMx zr*})I?&&u2In{Oou_;F zOVKJz7cnQ@(CC*xpbZ*sdA(*E=ZYKPV{_x%xGdwgjPFOF z0;5|hJpW#)bhdFGyy@w3;g5i5hz-pLEI9LKj0Ja!@TX4Gym@HfDLL=tbFTbkgUfoU zN1z^odIahbs7Ih4fqDe~A4Y)wjYy|LBau5jYg3+wIzk7A!;$F7=-Bw9$yEB#;fZ|! zz5AAk4_Sz{sdZ~ph^6D^hPygJ>Er(N1qWOaN*Ymjr4FVpq+mCzi7O-D{-;spM616@B|rX;H~jiim=ebB@$b)xV{tx@c9@n(IZ7G7|-rCq|!Q zROCO1zVPmAtkfKj3`c*~$T+x>mJ)`K46#bc^ zR}@{WlFV+jCYzx%lYX;DgIl-W>1jun^Btb9Ztr?;muG$F`tHu2&W)mmXmeMm{bDRU zjmIMKtC9thRT^KXaET*oqTH?&+zOvlxcof;7_koI$@+Uu#Zi+0F>w(vfmwyGQTUt< z|AfN7rToypYFw)I)9lxZa(+DP-ie9>vzq5W<2xk2TG+?=H^4nuO%s0BH0c8%*8Dz} z(pHcg5Fg(EA%AOuFpk5+N)~z)^=f{O)xf_&xYI58e#5RPiNV8+g`Pxx1^s%XgdDf? zz^k?U6W~e}wd>^rR9mXVq1jR0&n>`jyKY{teY%GJ9{{hGXT6VbXRG+UzwAO*VhZQ^ z&(cH6&n2bL_ov5!SG(RX0B^D6ce9^At)c&N4g8$)b3)Be_VZ6Q^xptpEr0w!Yv?a= zR`37KHE=I*8ZUd?HrCJ&*1(t6z@rj(36HuT$=~#F(T@=B#8VPeuA(3rK4o}^%^ynz zF(Nt^8WHixVUZXMi-RF!coeznxP|Hcnm%w}U|YYg_1!1*!J+NFfgyeSz`)M_UHYy- z?@&K-=ldSGH?S?ZRdA}jpYzBmW!#o%Pnq)-a!Qo104V!C_SG_Aa1$sD@&__e@ zFg6^7k|T#YRYJeb;y@~;x@6x=P*&{bEd*sm#unQF%9{)-B<8k)3dr0vPyxv;4P|7* z2DPQ3jF@du$asT7rO3XUp)AE-0=c_E$50wVcvD9X8leNAM$)9CT*KCiNOD|w;|U|; z9f_yC<4NptNE$~h(1COeo0no?1qFJ89R{YWR38ncMuj(gB#tIbY9vj`p-3_nOT;S} z9kOI(EJOyXHa=zuuk5DRh)kd^r=K^OkeBU^jOtNrs)*>LVc0TfTIiuSHprb^Lsqgb|s)bQta5C-=|~1sLO26-vvzhI{+%O*yH~wP^xH&G#Ss8CGVp1&iQE+|EA-+ujHQ}(?| zkH1Tp@^=i`)3=M={smwZ6ZT(zPO0Y=f3HDB7W??qe^^#~kFsMbh02zQ5|`;;*zMKx zlb@q!`GZgSV0*=izp~l$dmvN(9%X%d|G%s3IsU?)U%Bt7mP@h($ literal 0 HcmV?d00001 diff --git a/stuff/manual-programs/suckless/dmenu-5.2/stest.1 b/stuff/manual-programs/suckless/dmenu-5.2/stest.1 new file mode 100644 index 0000000..2667d8a --- /dev/null +++ b/stuff/manual-programs/suckless/dmenu-5.2/stest.1 @@ -0,0 +1,90 @@ +.TH STEST 1 dmenu\-VERSION +.SH NAME +stest \- filter a list of files by properties +.SH SYNOPSIS +.B stest +.RB [ -abcdefghlpqrsuwx ] +.RB [ -n +.IR file ] +.RB [ -o +.IR file ] +.RI [ file ...] +.SH DESCRIPTION +.B stest +takes a list of files and filters by the files' properties, analogous to +.IR test (1). +Files which pass all tests are printed to stdout. If no files are given, stest +reads files from stdin. +.SH OPTIONS +.TP +.B \-a +Test hidden files. +.TP +.B \-b +Test that files are block specials. +.TP +.B \-c +Test that files are character specials. +.TP +.B \-d +Test that files are directories. +.TP +.B \-e +Test that files exist. +.TP +.B \-f +Test that files are regular files. +.TP +.B \-g +Test that files have their set-group-ID flag set. +.TP +.B \-h +Test that files are symbolic links. +.TP +.B \-l +Test the contents of a directory given as an argument. +.TP +.BI \-n " file" +Test that files are newer than +.IR file . +.TP +.BI \-o " file" +Test that files are older than +.IR file . +.TP +.B \-p +Test that files are named pipes. +.TP +.B \-q +No files are printed, only the exit status is returned. +.TP +.B \-r +Test that files are readable. +.TP +.B \-s +Test that files are not empty. +.TP +.B \-u +Test that files have their set-user-ID flag set. +.TP +.B \-v +Invert the sense of tests, only failing files pass. +.TP +.B \-w +Test that files are writable. +.TP +.B \-x +Test that files are executable. +.SH EXIT STATUS +.TP +.B 0 +At least one file passed all tests. +.TP +.B 1 +No files passed all tests. +.TP +.B 2 +An error occurred. +.SH SEE ALSO +.IR dmenu (1), +.IR test (1) diff --git a/stuff/manual-programs/suckless/dmenu-5.2/stest.c b/stuff/manual-programs/suckless/dmenu-5.2/stest.c new file mode 100644 index 0000000..e27d3a5 --- /dev/null +++ b/stuff/manual-programs/suckless/dmenu-5.2/stest.c @@ -0,0 +1,109 @@ +/* See LICENSE file for copyright and license details. */ +#include + +#include +#include +#include +#include +#include +#include + +#include "arg.h" +char *argv0; + +#define FLAG(x) (flag[(x)-'a']) + +static void test(const char *, const char *); +static void usage(void); + +static int match = 0; +static int flag[26]; +static struct stat old, new; + +static void +test(const char *path, const char *name) +{ + struct stat st, ln; + + if ((!stat(path, &st) && (FLAG('a') || name[0] != '.') /* hidden files */ + && (!FLAG('b') || S_ISBLK(st.st_mode)) /* block special */ + && (!FLAG('c') || S_ISCHR(st.st_mode)) /* character special */ + && (!FLAG('d') || S_ISDIR(st.st_mode)) /* directory */ + && (!FLAG('e') || access(path, F_OK) == 0) /* exists */ + && (!FLAG('f') || S_ISREG(st.st_mode)) /* regular file */ + && (!FLAG('g') || st.st_mode & S_ISGID) /* set-group-id flag */ + && (!FLAG('h') || (!lstat(path, &ln) && S_ISLNK(ln.st_mode))) /* symbolic link */ + && (!FLAG('n') || st.st_mtime > new.st_mtime) /* newer than file */ + && (!FLAG('o') || st.st_mtime < old.st_mtime) /* older than file */ + && (!FLAG('p') || S_ISFIFO(st.st_mode)) /* named pipe */ + && (!FLAG('r') || access(path, R_OK) == 0) /* readable */ + && (!FLAG('s') || st.st_size > 0) /* not empty */ + && (!FLAG('u') || st.st_mode & S_ISUID) /* set-user-id flag */ + && (!FLAG('w') || access(path, W_OK) == 0) /* writable */ + && (!FLAG('x') || access(path, X_OK) == 0)) != FLAG('v')) { /* executable */ + if (FLAG('q')) + exit(0); + match = 1; + puts(name); + } +} + +static void +usage(void) +{ + fprintf(stderr, "usage: %s [-abcdefghlpqrsuvwx] " + "[-n file] [-o file] [file...]\n", argv0); + exit(2); /* like test(1) return > 1 on error */ +} + +int +main(int argc, char *argv[]) +{ + struct dirent *d; + char path[PATH_MAX], *line = NULL, *file; + size_t linesiz = 0; + ssize_t n; + DIR *dir; + int r; + + ARGBEGIN { + case 'n': /* newer than file */ + case 'o': /* older than file */ + file = EARGF(usage()); + if (!(FLAG(ARGC()) = !stat(file, (ARGC() == 'n' ? &new : &old)))) + perror(file); + break; + default: + /* miscellaneous operators */ + if (strchr("abcdefghlpqrsuvwx", ARGC())) + FLAG(ARGC()) = 1; + else + usage(); /* unknown flag */ + } ARGEND; + + if (!argc) { + /* read list from stdin */ + while ((n = getline(&line, &linesiz, stdin)) > 0) { + if (line[n - 1] == '\n') + line[n - 1] = '\0'; + test(line, line); + } + free(line); + } else { + for (; argc; argc--, argv++) { + if (FLAG('l') && (dir = opendir(*argv))) { + /* test directory contents */ + while ((d = readdir(dir))) { + r = snprintf(path, sizeof path, "%s/%s", + *argv, d->d_name); + if (r >= 0 && (size_t)r < sizeof path) + test(path, d->d_name); + } + closedir(dir); + } else { + test(*argv, *argv); + } + } + } + return match ? 0 : 1; +} diff --git a/stuff/manual-programs/suckless/dmenu-5.2/stest.o b/stuff/manual-programs/suckless/dmenu-5.2/stest.o new file mode 100644 index 0000000000000000000000000000000000000000..8a784affdaf889c703c02aacecb7b77ecedaa13a GIT binary patch literal 5256 zcmbW4Z){sv6~M3Uv^H($=eAi1tOKueAQR2Q&dQWdD~lUvxrTI9lx~xn)N$>XII3d@ z`@JPa>zc`SndiByps*o?x(Ox?flB#b3Dmi2*CMnJgHMwtjeV#D!D#J%)+J->U-x%ZuW-X9+un|R3WaxoGY`#fuFL>YTJ&>oN2!x0u>8r#cjyHMrz z&tVs7@Y?M-_zV8L>ZZ~DeZ2ZF{?y-wA$FSAw)YRf46pt;Gys5C|H12K$Y=Xh8m2eW zSh)TLYZ&ow3lgcH+aE?WH!|GF5+Dn(CFd2q&afF0?1x+X*$dobSQd zt9vo8t~?Kxy!1q9m}w_!Z7io`U9$;?++aPV`Dc3U0x{P({HaS=HwUIJLVQK6Vsh5F zKiFRk9vDm>N~MjN*-UoftA(QV_~OzOz+7-D>Vvpi^eeIYY->NS=Y0F1ga;tcP{Pg*d9@ts0}yFI@?eF6O=4R9X40#10G@tVf#M_lphgDWFY*|>T=?^}5f>#aT+3QRbUim}R7 zYe76Mc>M`X-P=ys8Y-2>lUsQ`=4~wxud_UtAtyGj-n4C+m!0lO4hgo0@#<^fV>n$<6!$XZtRGkXl)zTPSJOle8 z(tHWm{5X0?NzE5OXk2-bTT>>Js3?~WaFcw_Xh{YAKrgYFtS4* z(j&p4@X(I%&PbTyZ5o7z)dL31&0Gy+Brc(2qEULCj=8?}W#(E6xbE2C^__%CSdncN zbDzdO>JJP+7Zz+B?^R&O-BEvE$@2yO8*b0A+usK$>i0noV0u#69z@&S{=jqY-TuB4 zp56Xny(jJ;cy`U0KYV=cn18tB9rwQz^xW(A4@dpssDA)Vz!Y3|W32xrcpW|Ly;dh1 zPscYAV;(z8w|aa8RLIpTw67U7I6<3}ZeKSr%$p11ObeF`=qMk9hCGN0$VsPTcS4W6 zA#~z*3I00~M?NbLTPv*FowE=7+0ceC+HPxW;O%>>LVX2i(U9*T{!NeQ=CV;@To5RP#0bVzDdfPU3F| zDuZ1b*sNh@=W+&{DHsOJFBrM>T!9sgWE%TaHeWPwP|S(-;EM3xbp#&~erW%OCqBx0 ziQ||!J+IIn?@i)(-=SbUtS{nsBLqRd5gPG52tkl z{%fJ%6ulb%cH9Vv%0q(FKF{;P**!k)2f2ZIW zXM@DIN%nXzll`=0f1AX!692fwsorqiJ0$)+$sX6H=fV%9b@7^L-JeJt-`&JtmG~zl zPIZXuep2FZN$cXde4TXM1PIy(p;7!^!LgI~xvdLV>+Pb5FV~M;C%6_0#dkEuc8CFS z`retA_&PGiUN0V*HR~bC$kPfY(aFJR;nUOk$>xoHyis{h#9?_+jeQ zFRl?_C^?aTM{{gxj6K#Gp5+KMSw=+CI37L-)-bL^-&J^TpnM7%a$$zZmNUw_#Kkd_ zYJdM>Ox3?3{HZ?4AxHz!<98y)98x&>KcaA2pL%@G;8@My7O^4v4x=#SNBRg1I_2+a zOc=<3xDHft4K;uJfMLuqG+9jXsZ7r+nxplppM(h-lMVJKg}=;jtlDOQd7-JtMgHo( zX#W@sr3?*Ys{ReJ{wruCiRzEvv7PdF79aW`-0AH4!|y5br~2!(Ho9cQf%b`W#BVfg ksz1Je)Y=2Ymc@(dH>gOW<`3VAo%}x#`#&N1;!ySf50-Fd9{>OV literal 0 HcmV?d00001 diff --git a/stuff/manual-programs/suckless/dmenu-5.2/util.c b/stuff/manual-programs/suckless/dmenu-5.2/util.c new file mode 100644 index 0000000..96b82c9 --- /dev/null +++ b/stuff/manual-programs/suckless/dmenu-5.2/util.c @@ -0,0 +1,36 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include + +#include "util.h" + +void +die(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + if (fmt[0] && fmt[strlen(fmt)-1] == ':') { + fputc(' ', stderr); + perror(NULL); + } else { + fputc('\n', stderr); + } + + exit(1); +} + +void * +ecalloc(size_t nmemb, size_t size) +{ + void *p; + + if (!(p = calloc(nmemb, size))) + die("calloc:"); + return p; +} diff --git a/stuff/manual-programs/suckless/dmenu-5.2/util.h b/stuff/manual-programs/suckless/dmenu-5.2/util.h new file mode 100644 index 0000000..f633b51 --- /dev/null +++ b/stuff/manual-programs/suckless/dmenu-5.2/util.h @@ -0,0 +1,8 @@ +/* See LICENSE file for copyright and license details. */ + +#define MAX(A, B) ((A) > (B) ? (A) : (B)) +#define MIN(A, B) ((A) < (B) ? (A) : (B)) +#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B)) + +void die(const char *fmt, ...); +void *ecalloc(size_t nmemb, size_t size); diff --git a/stuff/manual-programs/suckless/dmenu-5.2/util.o b/stuff/manual-programs/suckless/dmenu-5.2/util.o new file mode 100644 index 0000000000000000000000000000000000000000..8e55fa18d6ada0bfba70d02362b40ffaf2d35ebf GIT binary patch literal 2224 zcmbtUO=uHQ5T0$TjWtbT?V(Z+5mrf{E}Ik~q$<%yyGoE+D{3#ACR-cKpPNldRWM>b zgb?V#qX!Qj6g(94C^YE7t4B}Pqfig^ASe~$%?e!*H_wR z+#gQLxBTIhT=s{b%5|js!_VYZOTUnxTl%%UX6d(b+tTmkPpGq6v+rmK4Gjy1B5kdC z3LW&mXss1_iv>os)~p=RT1i>`n3Mw^gi#NxEFAoX2Gl1&Yn~v>9Mc*b)Ud}2Xic>0 z4|+TC>cRCO#w|3`vDD_k`T&R4>1-_YvYq&(UG-`$t0N1T`;bZJ^QBB2U}|zQ9t=%g zx*85f#+9fN2}afExEfO#KRRyF-kt7tqjojnaLGz| z^@i91Tmi-r6@7;rexwT?>Vhj>aGJVXeVmikC-2WXC&VVY@S$qv@=6Aj)T9d8oDLN; zs~ZL^EtHL1(Of{^$m>N|C|Au4lrdB?K(FOY(Cv$XbxEqW!nxab;7`YvR}81SuooA{ z-!RcV5AE=@9h6{5Yy=>Xttsx zm@~xAiN_o+jADS!FTn{+*XXcOJS<^9+GN`A)BaCT{20R-oghnQoEtIR36CL8HUBlA z{(V$4ic1u}Kkt{v`2JicFhDl_*hQIR1pY7NF`mcu1q^VTb4V|_fiBz|h|xO}?<%@b zWBJa$oZoX7xkPp5zhwE-R7? +© 2006-2009 Jukka Salmi +© 2006-2007 Sander van Dijk +© 2007-2011 Peter Hartlich +© 2007-2009 Szabolcs Nagy +© 2007-2009 Christof Musik +© 2007-2009 Premysl Hruby +© 2007-2008 Enno Gottox Boland +© 2008 Martin Hurton +© 2008 Neale Pickett +© 2009 Mate Nagy +© 2010-2016 Hiltjo Posthuma +© 2010-2012 Connor Lane Smith +© 2011 Christoph Lohmann <20h@r-36.net> +© 2015-2016 Quentin Rameau +© 2015-2016 Eric Pruitt +© 2016-2017 Markus Teich + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/stuff/manual-programs/suckless/dwm-bak/Makefile b/stuff/manual-programs/suckless/dwm-bak/Makefile new file mode 100644 index 0000000..77bcbc0 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/Makefile @@ -0,0 +1,51 @@ +# dwm - dynamic window manager +# See LICENSE file for copyright and license details. + +include config.mk + +SRC = drw.c dwm.c util.c +OBJ = ${SRC:.c=.o} + +all: options dwm + +options: + @echo dwm build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +.c.o: + ${CC} -c ${CFLAGS} $< + +${OBJ}: config.h config.mk + +config.h: + cp config.def.h $@ + +dwm: ${OBJ} + ${CC} -o $@ ${OBJ} ${LDFLAGS} + +clean: + rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz + +dist: clean + mkdir -p dwm-${VERSION} + cp -R LICENSE Makefile README config.def.h config.mk\ + dwm.1 drw.h util.h ${SRC} dwm.png transient.c dwm-${VERSION} + tar -cf dwm-${VERSION}.tar dwm-${VERSION} + gzip dwm-${VERSION}.tar + rm -rf dwm-${VERSION} + +install: all + mkdir -p ${DESTDIR}${PREFIX}/bin + cp -f dwm ${DESTDIR}${PREFIX}/bin + chmod 755 ${DESTDIR}${PREFIX}/bin/dwm + mkdir -p ${DESTDIR}${MANPREFIX}/man1 + sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1 + chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1 + +uninstall: + rm -f ${DESTDIR}${PREFIX}/bin/dwm\ + ${DESTDIR}${MANPREFIX}/man1/dwm.1 + +.PHONY: all options clean dist install uninstall diff --git a/stuff/manual-programs/suckless/dwm-bak/README b/stuff/manual-programs/suckless/dwm-bak/README new file mode 100644 index 0000000..95d4fd0 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/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/stuff/manual-programs/suckless/dwm-bak/awesome-glyphs.txt b/stuff/manual-programs/suckless/dwm-bak/awesome-glyphs.txt new file mode 100644 index 0000000..7541568 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/awesome-glyphs.txt @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/stuff/manual-programs/suckless/dwm-bak/config.def.h.orig b/stuff/manual-programs/suckless/dwm-bak/config.def.h.orig new file mode 100644 index 0000000..5312ecb --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/config.def.h.orig @@ -0,0 +1,142 @@ +/* See LICENSE file for copyright and license details. */ + +/* appearance */ +static const unsigned int borderpx = 2; /* border pixel size of windows */ +static const unsigned int gappx = 5; /* gaps size between windows */ +static const unsigned int snap = 32; /* snap pixel */ +static const int showbar = 1; /* 0 means no bar */ +static const int topbar = 1; /* 0 means bottom bar */ +static const char *fonts[] = { "monospace:size=12", "fontawesome:size=12" }; +static const char dmenufont[] = "monospace:size=11"; +//background color +static const char col_gray1[] = "#222222"; +//inactive window border color +static const char col_gray2[] = "#444444"; +//font color +static const char col_gray3[] = "#bbbbbb"; +//current tag and current window font color +static const char col_gray4[] = "#eeeeee"; +//Top bar second color (blue) and active window border color +static const char col_cyan[] = "#f59542"; +static const char *colors[][3] = { + /* fg bg border */ + [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, + [SchemeSel] = { col_gray4, col_cyan, col_cyan }, +}; + +/* tagging */ +//tag names (upper left) +static const char *tags[] = { "", "", "", "", "", "", "", "", "", "" }; + +static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ + /* class instance title tags mask isfloating monitor */ + { "Gimp", NULL, NULL, 0, 1, -1 }, + { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, +}; + +/* layout(s) */ +static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ +static const int nmaster = 1; /* number of clients in master area */ +static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ + +static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, +}; + +/* 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 } } + +/* commands */ +static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ +static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; +//static const char *filemanager[] = { " +//launches htop +static const char *monitor[] = { "/usr/bin/htop", NULL }; +//sets st as the default terminal +//static const char *termcmd[] = { "st", NULL }; +//sets urxvt as the default terminal +static const char *termcmd[] = { "urxvt", NULL }; +//volume controls +static const char *upvol[] = { "amixer", "-q", "set", "Master", "5%+", "unmute", NULL }; +static const char *downvol[] = { "amixer", "-q", "set", "Master", "5%-", "unmute", NULL }; +static const char *mutevol[] = { "amixer", "-q", "set", "Master", "toggle", NULL }; + +#include "shiftview.c" +static char *endx[] = { "/bin/sh", "-c", "endx", "externalpipe", NULL }; +static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_d, spawn, {.v = dmenucmd } }, + { MODKEY, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_t, togglebar, {0} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, + { MODKEY, XK_u, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, + { MODKEY, XK_z, zoom, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY, XK_q, killclient, {0} }, + { MODKEY|ShiftMask, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY|ShiftMask, XK_f, setlayout, {.v = &layouts[1]} }, + { MODKEY|ShiftMask, XK_m, setlayout, {.v = &layouts[2]} }, + { MODKEY|ShiftMask, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, + { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, + { MODKEY, XK_comma, focusmon, {.i = -1 } }, + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY, XK_minus, setgaps, {.i = -1 } }, + { MODKEY, XK_equal, setgaps, {.i = +1 } }, + { MODKEY|ShiftMask, XK_equal, setgaps, {.i = 0 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + { MODKEY, XK_n, shiftview, { .i = +1 } }, + { MODKEY, XK_b, shiftview, { .i = -1 } }, + { MODKEY, XK_F8, spawn, {.v = upvol } }, + { MODKEY, XK_F7, spawn, {.v = downvol } }, + { MODKEY, XK_F5, spawn, {.v = mutevol } }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) + TAGKEYS( XK_4, 3) + TAGKEYS( XK_5, 4) + TAGKEYS( XK_6, 5) + TAGKEYS( XK_7, 6) + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) + { MODKEY|ShiftMask, XK_q, quit, {0} }, +}; + +/* button definitions */ +/* 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} }, +}; + diff --git a/stuff/manual-programs/suckless/dwm-bak/config.h b/stuff/manual-programs/suckless/dwm-bak/config.h new file mode 100644 index 0000000..c9b7665 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/config.h @@ -0,0 +1,146 @@ +/* See LICENSE file for copyright and license details. */ + +/* appearance */ +static const unsigned int borderpx = 2; /* border pixel size of windows */ +static const unsigned int gappx = 5; /* gaps size between 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 = 0; /* 0 means bottom bar */ +static const char *fonts[] = { "monospace:size=12", "fontawesome:size=12" }; +static const char dmenufont[] = "monospace:size=11"; +//background color +static const char col_gray1[] = "#222222"; +//inactive window border color +static const char col_gray2[] = "#444444"; +//font color +static const char col_gray3[] = "#bbbbbb"; +//current tag and current window font color +static const char col_gray4[] = "#eeeeee"; +//Top bar second color (blue) and active window border color +static const char col_cyan[] = "#8558e6"; +static const char *colors[][3] = { + /* fg bg border */ + [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, + [SchemeSel] = { col_gray4, col_cyan, col_cyan }, +}; + +/* tagging */ +//tag names (upper left) +static const char *tags[] = { "", "", "", "", "", "", "", "", "", "" }; + +static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ + /* class instance title tags mask isfloating monitor */ + { "Gimp", NULL, NULL, 0, 1, -1 }, + { "Firefox", NULL, NULL, 1 << 8, 1, -1 }, +}; + +/* layout(s) */ +static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ +static const int nmaster = 1; /* number of clients in master area */ +static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ + +static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, +}; + +/* 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 } } + +/* commands */ +static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ +static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; +//static const char *filemanager[] = { " +//launches htop +static const char *monitor[] = { "/usr/bin/htop", NULL }; +//sets st as the default terminal +//static const char *termcmd[] = { "st", NULL }; +//sets urxvt as the default terminal +static const char *termcmd[] = { "urxvt", NULL }; +//volume controls +static const char *upvol[] = { "amixer", "-q", "set", "Master", "5%+", "unmute", NULL }; +static const char *downvol[] = { "amixer", "-q", "set", "Master", "5%-", "unmute", NULL }; +static const char *mutevol[] = { "amixer", "-q", "set", "Master", "toggle", NULL }; + +#include "shiftview.c" +static char *endx[] = { "/bin/sh", "-c", "endx", "externalpipe", NULL }; +static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_d, spawn, {.v = dmenucmd } }, + { MODKEY, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_t, togglebar, {0} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, + { MODKEY, XK_u, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, + { MODKEY, XK_z, zoom, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY, XK_q, killclient, {0} }, + { MODKEY|ShiftMask, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY|ShiftMask, XK_f, setlayout, {.v = &layouts[1]} }, + { MODKEY|ShiftMask, XK_m, setlayout, {.v = &layouts[2]} }, + { MODKEY|ShiftMask, XK_space, setlayout, {0} }, + { MODKEY, XK_space, togglefloating, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, + { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, + { MODKEY, XK_comma, focusmon, {.i = -1 } }, + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY, XK_minus, setgaps, {.i = -1 } }, + { MODKEY, XK_equal, setgaps, {.i = +1 } }, + { MODKEY|ShiftMask, XK_equal, setgaps, {.i = 0 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + { MODKEY, XK_n, shiftview, { .i = +1 } }, + { MODKEY, XK_b, shiftview, { .i = -1 } }, + { MODKEY, XK_F8, spawn, {.v = upvol } }, + { MODKEY, XK_F7, spawn, {.v = downvol } }, + { MODKEY, XK_F5, spawn, {.v = mutevol } }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) + TAGKEYS( XK_4, 3) + TAGKEYS( XK_5, 4) + TAGKEYS( XK_6, 5) + TAGKEYS( XK_7, 6) + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) + { MODKEY|ShiftMask, XK_q, quit, {0} }, +}; + +/* button definitions */ +/* 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} }, +}; + diff --git a/stuff/manual-programs/suckless/dwm-bak/config.mk b/stuff/manual-programs/suckless/dwm-bak/config.mk new file mode 100644 index 0000000..6d36cb7 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/config.mk @@ -0,0 +1,38 @@ +# dwm version +VERSION = 6.2 + +# Customize below to fit your system + +# paths +PREFIX = /usr/local +MANPREFIX = ${PREFIX}/share/man + +X11INC = /usr/X11R6/include +X11LIB = /usr/X11R6/lib + +# Xinerama, comment if you don't want it +XINERAMALIBS = -lXinerama +XINERAMAFLAGS = -DXINERAMA + +# freetype +FREETYPELIBS = -lfontconfig -lXft +FREETYPEINC = /usr/include/freetype2 +# OpenBSD (uncomment) +#FREETYPEINC = ${X11INC}/freetype2 + +# includes and libs +INCS = -I${X11INC} -I${FREETYPEINC} +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} + +# flags +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +#CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} +CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS} +LDFLAGS = ${LIBS} + +# Solaris +#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\" +#LDFLAGS = ${LIBS} + +# compiler and linker +CC = cc diff --git a/stuff/manual-programs/suckless/dwm-bak/drw.c b/stuff/manual-programs/suckless/dwm-bak/drw.c new file mode 100644 index 0000000..8fd1ca4 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/drw.c @@ -0,0 +1,435 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include + +#include "drw.h" +#include "util.h" + +#define UTF_INVALID 0xFFFD +#define UTF_SIZ 4 + +static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; +static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; +static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; +static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; + +static long +utf8decodebyte(const char c, size_t *i) +{ + for (*i = 0; *i < (UTF_SIZ + 1); ++(*i)) + if (((unsigned char)c & utfmask[*i]) == utfbyte[*i]) + return (unsigned char)c & ~utfmask[*i]; + return 0; +} + +static size_t +utf8validate(long *u, size_t i) +{ + if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) + *u = UTF_INVALID; + for (i = 1; *u > utfmax[i]; ++i) + ; + return i; +} + +static size_t +utf8decode(const char *c, long *u, size_t clen) +{ + size_t i, j, len, type; + long udecoded; + + *u = UTF_INVALID; + if (!clen) + return 0; + udecoded = utf8decodebyte(c[0], &len); + if (!BETWEEN(len, 1, UTF_SIZ)) + return 1; + for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { + udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); + if (type) + return j; + } + if (j < len) + return 0; + *u = udecoded; + utf8validate(u, len); + + return len; +} + +Drw * +drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h) +{ + Drw *drw = ecalloc(1, sizeof(Drw)); + + drw->dpy = dpy; + drw->screen = screen; + drw->root = root; + drw->w = w; + drw->h = h; + drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); + drw->gc = XCreateGC(dpy, root, 0, NULL); + XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); + + return drw; +} + +void +drw_resize(Drw *drw, unsigned int w, unsigned int h) +{ + if (!drw) + return; + + drw->w = w; + drw->h = h; + if (drw->drawable) + XFreePixmap(drw->dpy, drw->drawable); + drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen)); +} + +void +drw_free(Drw *drw) +{ + XFreePixmap(drw->dpy, drw->drawable); + XFreeGC(drw->dpy, drw->gc); + free(drw); +} + +/* This function is an implementation detail. Library users should use + * drw_fontset_create instead. + */ +static Fnt * +xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) +{ + Fnt *font; + XftFont *xfont = NULL; + FcPattern *pattern = NULL; + + if (fontname) { + /* Using the pattern found at font->xfont->pattern does not yield the + * same substitution results as using the pattern returned by + * FcNameParse; using the latter results in the desired fallback + * behaviour whereas the former just results in missing-character + * rectangles being drawn, at least with some fonts. */ + if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) { + fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname); + return NULL; + } + if (!(pattern = FcNameParse((FcChar8 *) fontname))) { + fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname); + XftFontClose(drw->dpy, xfont); + return NULL; + } + } else if (fontpattern) { + if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) { + fprintf(stderr, "error, cannot load font from pattern.\n"); + return NULL; + } + } else { + die("no font specified."); + } + + /* Do not allow using color fonts. This is a workaround for a BadLength + * error from Xft with color glyphs. Modelled on the Xterm workaround. See + * https://bugzilla.redhat.com/show_bug.cgi?id=1498269 + * https://lists.suckless.org/dev/1701/30932.html + * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916349 + * and lots more all over the internet. + */ + FcBool iscol; + if(FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) { + XftFontClose(drw->dpy, xfont); + return NULL; + } + + font = ecalloc(1, sizeof(Fnt)); + font->xfont = xfont; + font->pattern = pattern; + font->h = xfont->ascent + xfont->descent; + font->dpy = drw->dpy; + + return font; +} + +static void +xfont_free(Fnt *font) +{ + if (!font) + return; + if (font->pattern) + FcPatternDestroy(font->pattern); + XftFontClose(font->dpy, font->xfont); + free(font); +} + +Fnt* +drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount) +{ + Fnt *cur, *ret = NULL; + size_t i; + + if (!drw || !fonts) + return NULL; + + for (i = 1; i <= fontcount; i++) { + if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) { + cur->next = ret; + ret = cur; + } + } + return (drw->fonts = ret); +} + +void +drw_fontset_free(Fnt *font) +{ + if (font) { + drw_fontset_free(font->next); + xfont_free(font); + } +} + +void +drw_clr_create(Drw *drw, Clr *dest, const char *clrname) +{ + if (!drw || !dest || !clrname) + return; + + if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen), + DefaultColormap(drw->dpy, drw->screen), + clrname, dest)) + die("error, cannot allocate color '%s'", clrname); +} + +/* Wrapper to create color schemes. The caller has to call free(3) on the + * returned color scheme when done using it. */ +Clr * +drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) +{ + size_t i; + Clr *ret; + + /* need at least two colors for a scheme */ + if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor)))) + return NULL; + + for (i = 0; i < clrcount; i++) + drw_clr_create(drw, &ret[i], clrnames[i]); + return ret; +} + +void +drw_setfontset(Drw *drw, Fnt *set) +{ + if (drw) + drw->fonts = set; +} + +void +drw_setscheme(Drw *drw, Clr *scm) +{ + if (drw) + drw->scheme = scm; +} + +void +drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert) +{ + if (!drw || !drw->scheme) + return; + XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel); + if (filled) + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); + else + XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1); +} + +int +drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert) +{ + char buf[1024]; + int ty; + unsigned int ew; + XftDraw *d = NULL; + Fnt *usedfont, *curfont, *nextfont; + size_t i, len; + int utf8strlen, utf8charlen, render = x || y || w || h; + long utf8codepoint = 0; + const char *utf8str; + FcCharSet *fccharset; + FcPattern *fcpattern; + FcPattern *match; + XftResult result; + int charexists = 0; + + if (!drw || (render && !drw->scheme) || !text || !drw->fonts) + return 0; + + if (!render) { + w = ~w; + } else { + XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); + d = XftDrawCreate(drw->dpy, drw->drawable, + DefaultVisual(drw->dpy, drw->screen), + DefaultColormap(drw->dpy, drw->screen)); + x += lpad; + w -= lpad; + } + + usedfont = drw->fonts; + while (1) { + utf8strlen = 0; + utf8str = text; + nextfont = NULL; + while (*text) { + utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); + for (curfont = drw->fonts; curfont; curfont = curfont->next) { + charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); + if (charexists) { + if (curfont == usedfont) { + utf8strlen += utf8charlen; + text += utf8charlen; + } else { + nextfont = curfont; + } + break; + } + } + + if (!charexists || nextfont) + break; + else + charexists = 0; + } + + if (utf8strlen) { + drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL); + /* shorten text if necessary */ + for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--) + drw_font_getexts(usedfont, utf8str, len, &ew, NULL); + + if (len) { + memcpy(buf, utf8str, len); + buf[len] = '\0'; + if (len < utf8strlen) + for (i = len; i && i > len - 3; buf[--i] = '.') + ; /* NOP */ + + if (render) { + ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; + XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], + usedfont->xfont, x, ty, (XftChar8 *)buf, len); + } + x += ew; + w -= ew; + } + } + + if (!*text) { + break; + } else if (nextfont) { + charexists = 0; + usedfont = nextfont; + } else { + /* Regardless of whether or not a fallback font is found, the + * character must be drawn. */ + charexists = 1; + + fccharset = FcCharSetCreate(); + FcCharSetAddChar(fccharset, utf8codepoint); + + if (!drw->fonts->pattern) { + /* Refer to the comment in xfont_create for more information. */ + die("the first font in the cache must be loaded from a font string."); + } + + fcpattern = FcPatternDuplicate(drw->fonts->pattern); + FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); + FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); + FcPatternAddBool(fcpattern, FC_COLOR, FcFalse); + + FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); + FcDefaultSubstitute(fcpattern); + match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result); + + FcCharSetDestroy(fccharset); + FcPatternDestroy(fcpattern); + + if (match) { + usedfont = xfont_create(drw, NULL, match); + if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) { + for (curfont = drw->fonts; curfont->next; curfont = curfont->next) + ; /* NOP */ + curfont->next = usedfont; + } else { + xfont_free(usedfont); + usedfont = drw->fonts; + } + } + } + } + if (d) + XftDrawDestroy(d); + + return x + (render ? w : 0); +} + +void +drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) +{ + if (!drw) + return; + + XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y); + XSync(drw->dpy, False); +} + +unsigned int +drw_fontset_getwidth(Drw *drw, const char *text) +{ + if (!drw || !drw->fonts || !text) + return 0; + return drw_text(drw, 0, 0, 0, 0, 0, text, 0); +} + +void +drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h) +{ + XGlyphInfo ext; + + if (!font || !text) + return; + + XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext); + if (w) + *w = ext.xOff; + if (h) + *h = font->h; +} + +Cur * +drw_cur_create(Drw *drw, int shape) +{ + Cur *cur; + + if (!drw || !(cur = ecalloc(1, sizeof(Cur)))) + return NULL; + + cur->cursor = XCreateFontCursor(drw->dpy, shape); + + return cur; +} + +void +drw_cur_free(Drw *drw, Cur *cursor) +{ + if (!cursor) + return; + + XFreeCursor(drw->dpy, cursor->cursor); + free(cursor); +} diff --git a/stuff/manual-programs/suckless/dwm-bak/drw.h b/stuff/manual-programs/suckless/dwm-bak/drw.h new file mode 100644 index 0000000..4bcd5ad --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/drw.h @@ -0,0 +1,57 @@ +/* See LICENSE file for copyright and license details. */ + +typedef struct { + Cursor cursor; +} Cur; + +typedef struct Fnt { + Display *dpy; + unsigned int h; + XftFont *xfont; + FcPattern *pattern; + struct Fnt *next; +} Fnt; + +enum { ColFg, ColBg, ColBorder }; /* Clr scheme index */ +typedef XftColor Clr; + +typedef struct { + unsigned int w, h; + Display *dpy; + int screen; + Window root; + Drawable drawable; + GC gc; + Clr *scheme; + Fnt *fonts; +} Drw; + +/* Drawable abstraction */ +Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h); +void drw_resize(Drw *drw, unsigned int w, unsigned int h); +void drw_free(Drw *drw); + +/* Fnt abstraction */ +Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount); +void drw_fontset_free(Fnt* set); +unsigned int drw_fontset_getwidth(Drw *drw, const char *text); +void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h); + +/* Colorscheme abstraction */ +void drw_clr_create(Drw *drw, Clr *dest, const char *clrname); +Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount); + +/* Cursor abstraction */ +Cur *drw_cur_create(Drw *drw, int shape); +void drw_cur_free(Drw *drw, Cur *cursor); + +/* Drawing context manipulation */ +void drw_setfontset(Drw *drw, Fnt *set); +void drw_setscheme(Drw *drw, Clr *scm); + +/* Drawing functions */ +void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert); +int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert); + +/* Map functions */ +void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); diff --git a/stuff/manual-programs/suckless/dwm-bak/drw.o b/stuff/manual-programs/suckless/dwm-bak/drw.o new file mode 100644 index 0000000000000000000000000000000000000000..d50849c84d232d43796b22bb1729dec68f8c7b8f GIT binary patch literal 10488 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 N4yEe6CZ6v8{{!H+P-y@F literal 0 HcmV?d00001 diff --git a/stuff/manual-programs/suckless/dwm-bak/dwm b/stuff/manual-programs/suckless/dwm-bak/dwm new file mode 100644 index 0000000000000000000000000000000000000000..c68255534f0a206c1fcc95709f2f93bef3f93ba2 GIT binary patch literal 74816 zcmeFadw5e-_CI_|8wd!dXwm9$2@=OvKw6HR75=?Tq-D3yyX3?z0YY6k$m6xd7tO^ zJik8-Hv6p4UVH7e*S@d4Ph64X8s9B0PS8K`!mR>PiBmX|rA5^D@8Zc4GKD@umM};d zD0D}B0{(Qq=bg@27BYBJ-3W=PibS8St zqAz^1*mq}`H=ombXiUfQ+o17Bg>?fsu7}2SWE<~c9v>YhCUHFTY98w8$Xt|e-KQLn z4y~F!^-#Ab=}3Q>nmwb#EH19I*wN|gv~YHw6Dp0aC{85{lFln05tzKv*Oiv#t#4)-jF#2@UXg!{IsR>YVDSg6{z_cSb zJUQ^H?3E)6RmW!^jbD45c&HqdhIr^h82#xVY7Q&#M?B0vJOkEB2)Cb6^ezPIm!I({ zz!krQh3PTy^~n5E{LetfrSQejGNs~edfo&&&QDSW(@qH7ZKtDKg=Ll@fZEs9;3XyV(9;33_ahBA!lj~{F4}R z{wGGc(qiaS9z*^x6x14BSkU*zkY9_qOSQvyW3-=TG4zpQ$o~WMyzUbEgk$hekAc_4 z(C57v`W%jd2V%6tJ7U=3Pz-&_V(`z4!GC#-`l^nBXT*?mAO`;vG3@hT3^|{~;4g|{ zw?i@V-5aAl|0f3jwK3$s6GP7_G4wndqaJt0kn?g3{M#7%B*(~Cj8U#HVzh^!W7wxH zhMbHT{J)98KO%-5#>dcSZ4Car7G58;k zQLf*|(DS+&@^6nJKO=^mhhvm?dklR_W7wfNhMc!z=yQ1t{4X)&e;q^rp)vS-#o*71 zk?((F=-(1U{-0ym|K1q<>tpomTVv>XR}B8EV&q#9qg=%?#jxwNn146n0G-nQCw%9kGrC7 zQHht-s4B}@453UT7^T+ZtX@);S6xOWK;drpKv@(e-&2XARa93^UQ$IFK>yq-uOG^k z`fH(mIZExBUQtz6y+riEM05Q<4{))pte`r-WU&YQOwJ`(Dl4m(Fde{;oRD|Lyb4cE zUWwNWOAE~EI>?lEdTM<&)l0c3p%9Gv<5Z8gqz0wYX^7*GUA2(!_j;>qe6_CX(h{mB zZjTAsyttipiQ@V^U8%?voyK)~=2cXA^lG9!@~A?fK5r16jMQF`1GB23;}BwF|YnrNkHMJE^*6 zQAwqy^;FNi8c%IG63wkHsVVC;JnGDaf*R`+aryqaOISUlyyGh>D-BJ45?WbTYwENL zoQfu*)E;Oi@UF}^eqWuenQ~aKqr3K7vNcD?Gx3sF1njSSp*7{KS)r&n- zJ+&2gcNz-m&_g`)YpVTKWqSSQS1j^YcCxT4L*@FaORFnU43xZf>7s&agr%(IYYz-T z3~OVoHb@|A>RnBPsoYuRx5FaYmDEl3to3@LI-q7o8tWLWTT`;AB)3*X-&%~eq5({1 zekoE^)e7TF(cnt_l|ER$)>q*}&jRKy@zL;rqKvDquIvKP<1PlAes5((DaID?K=&Hh zhqrmqlS&qO+$A-&ERHq5i}KLewf@$X9(hnySEgMYnpzqM@)8Q?v2ie`&IhB^PV>#n zB!~t}K9m{}O)tyo3K};Jwwf-w0D`E% zI-OVID=il=l$3gx3bj>UjO)I60tRag%LG?3+~cdQD8n3q>7jJtoYL}zbLN#)R0`-Z z9>G&r;S*|?Vn$gc%&V?hNU174RTSVqM0-jXdyy92v{G$;SyWO%@#qFMh$yWqnS-&U zq!R5{sP*_zCK{CRg(snum3SUT*-~NgJWanPB^5p|G$OcGsI8cf)RbZABCmja3e(fc zO?L}>)>;z*=>*J!8B19;cS0~1ck7XkJmmye?zrqZH{UdJl%PL$J>7g$2If`x_YD8K zk$(^W_&1NyF`dsCcQMw*c`?t$l%9s?(iKNfU6jrh->FYmoc^STIxi1(ltSZk0+VFq z#gY?PyfCB(_fOI~drjPD_?OdNs<#?Uu zFW2!6+Brmh6n-~t0PtBIg*SLO-V}u|*Z9{(;rD6y`Y1fz$K^Cf;lJ1T)hJxiaO)>L zov#0*8lDn`uhsChDEtWx&y2#K*6^$-{8HNu2xISK|Md3PsW)$Apo}+M`-y4PN?XW2d*UP&h3fJ3J zYZNYN{iQtyo~T}2-fnt5#=zY%aBmcTkJewBV&EI1@D#26x5mKRqj0^QcSPaETE9pP zU0g1mKRF7wYW!(YxXzy$g}0sLa@|q5UN7D#TptITqHw*wHbmk2IM5n}>+;*9a9w`l z@r%o=%TJ5Kb@}cnT$k^S!gcvgQMfLDLlmydZ;irr`R!4-EX zT$kSzg?H*7h3oQLqi|h*dlatAPdpJr|0rCS?~cNC`Q9j8m){hHcj_O7>+)Npa9w_T z6t2rp)Y`R~7emnHr$ynqe0LPC%lAg%y8NanT$jHg3fJYgM&VnFxng?%)Abzo3dhwb z{*fBq9))-RH|Ot&!f(;|1#LXg2_))*XK10KIN8zO!-Wr9s zYwOE{QTRNKzby*i@T%4xqVNS8e|r?ZPUG*0!mBiXA<8e^r16`h@EVOjF$%BO_>-gX z#Tvgg3SX`9XGP(9zETvf>+g=jAJ^m*M&Y{r;wW6#vpfdwjlwr;`qxF_?`nAS5nd17 z5%lGc?0dHXA7a2;4ft>ae$aqxSLIl2n*m>J;IG&8F#%g)z=bwW^gw{4i_VX^jXx4j zeggfI*v6j-$B{|rC%KJ35}weB3WC*uQ{MU~rHwxkKiNY6q_y!U!s$={WVZ1q!t}9* zkgPWP=Da=mBm0)xI6?fq_#^vvw{e2-%lISvE^Olj;l24I`z~(d1mS)7Bl|9I;{@TC z^GEjWZQ}&t7XHY->)JR$xPGUNkoq?I=K34&TdZzlFtfpx{E>Y(8So?n{_B;E4wOdIO$pz<+DNtp@xC1D;~QQw(^T0Z%pH znFjnu1D<8ThZ=CnfDbd^ZUcUk0WUP*BMf-40jGPC`lsB0r|Td>uK~Z=fY%xDQ3kx; zfM*!+)du_)1Kwo7e`mlSH{h8De4PQe8}Ri8e6#`IV8F*1@Qnt1tO0K};0^=6+koF{ zz*`OYZ3g_H0nakvZ3bL4;Hm*1XTaMHc(wuWFyKxDE*#|qwf`IgZZ_cK4S1pfpJ2d~ z4Y*{$tp+^TfTtMni3U8)fZuMwGYz=QfM*%-JOeHn@JR;TZNMiR@InLbHsHkue2M`t zH{hDfo5gw!c)o$Z&VUyf@OlG2&48~q;CC4CCIdd*fIn`)3k~=>13trmuQ%W`4fqBF zUSz;G8t_>LyxD-?X~1_I@Yx2u)qu}2;0FzOu>o&0;3WoJHQ;j%c)I~FHQ*fvyv%?L zUvPrjzsG=^4fs3*o@l`58}MWUUT(mx2E4+6rx@@B20YDxFErqp2E5XMXBqHC23#`W zRR-K`z^e^-p#k?A@L~ggmjN#~;57!^Yrty_c%1?F8Sr`o?l<784fqlR-ekb*4EW;) ze5nCnXTa|^;Oh;z<|1dY8w~g|1OG+?uDJqPY_kDhZs7m*@mCA{YJp!Z@T&!WwZN|y z_|*cxTHsd;{Az(;E%1NJ0%t7)FGztCW=S#q`)NUt8k>FHBCS$jhq;Ai8OhiSICA|v z__hqn!V}SKry6RD;B)<prfqh}%jo-wHWOXU==+E!7kKT0n(N`1gWppp1$;BQjW^^~A z$+aGGGy1~+fF_rED2vf&h$dHhD2>s_i6$3%$ja!WL=PZ3kxd>7cBqNb*Ah*x>rg$TuOOOS)*&yWdl5~p>QFJGyAe$;>X4h!7oGx5 zuIW$~qt6gcF6mGjqmL6!uIP}J(MO4P5S_^AkBPpOXo1oDiN1~K_8(aN6P-nL8>6=q zEfU?z=uJeABf6QYr$G^@iFQJ&tH{@rGI%J(_58?S`5eeKXPI(hY53^o>N5D>t-`(bo}8 zF5FNPqpu~JT(_ZmMqfcRxoksTM)x9`T(zNMMt38cT(luKqc1!Onq0G?EJmLpnq0D> zG)5mMdKS@EMjs{mPNEYT{V~zAi53{WpXfP6w|~#-pXg$u+Zer_XmYWJS{c2G=($8U zGx{Z>ONrjV=zkDRuGG*vMn6L|xllt*jQ$hRYyGWvd^X#xrrGx|QF zD~NV8`fj2Z5S_*78lo2xoyO<|M3XBtWM%YRqR9msN@Vm*qRI6c5*R&|XmWXm+B;bN z6HTtpP#dGi5lt@6P%EQH6HTtoP&1=%CYoHDp$&|_k!W&dhSo9qI-<#i8ERtmwL~u_ zx}MQj5KXSkkeAWDh$a_is2H?3UA#k_CKgP~msXyjm)grDCEE}MRbsGPt}Zef_1~u^oaT?OeV>utJbrngugd9KO)X;Xkd6Y z4aReba#tK@AZQaEYJ>kX;xAp*MrvmkLjQt46gCaQ;#2e@~DJN=yc6H!6OBbeXR zKXW<%;4xny1`6DXks9oe0n`P`J7v=!DFdTqccLOCJC&^dlH5-Mv)rc!EKb=pAA$OK zFX%>V7%7-B@vjKvUC=TUeCiXIfrKrnX#J>YU(Eubn0`Y!Dp{FImYJ77(A-Tn^&@FA z*C`Gh>H8tEqa0v123IJ00@4|H8ep!xLmkTT4|Mz(aOAy)^0x4}je6Ygkw4<h-u6d0ZjIZRT-hdfZ=m9OIfcpP>)-~Aq-m!`+jaD;l;P3ac$ zxFkL9P9FCP#ZBgM9nWcH&*gE+6gQH`eWJ%@@VEquyPC&sMBEl9wMyCaEuPgYvFxOB z6HX%n@aGBt0n1b1s|lx-2Jj~d{{r|HGk~qEZOf(y2_1;Z0o*h3youK7XraG-mJ+of zT>)|2)01&z8aVnhj(ABKa5HhtAPzYjBg}v^h*AH91&n&`dVFofQUt@sF`(&tkj)Qx zm@2-3feGzi+(_X9_D_BIJJe!ehczdC&l?yggavVu(r*-`OY%-}qZLR#(r;!Nn;xKC zR?uh@G(BGiW~kEdJU}-xt40VZF8OmLxF3YLkxH#jCVrj+xDO$M^2m_zz;f)$Wf~xr z<_C!XBk}b?f+jqW_+*5nWCCO&gH(__rFse@G8lIO0blzw2#_6kOoRky*{rVMGF!4M z=(CyCbSkf6xRmg0B;Ao66|ZRc_Sd%oXbp@w|F!+xkMUqxz+_)KcaH&oq@J!nm?;PBEQ z@_XeRGiCzBosyJ3%OD0?K89eEP|s8iQMnXH4aI=HhkC{e z=95tCY2GZ#5tDuxGk!I(C~4~N&Qc0fJ&(@S&~4lR3xKLQ?AiAzUl8;J(W9{yOob+alTtUaf=wXq5|9nsozU@i@ z+>Q+xh6&o|N%jsO7D=WmFp(>zXQa(CsGcOZXd(D}GX4zOw@Il#OLDuk?bL13wvKoy zZl|>GXI~NoWM~4+k+yl3LC&u9q+h+`U99;9|Hx@lz;OjQ(W$@mVT5vA^$2`5{RBX2 zDU{u5dJc?ncN$9AGOtT_^5>Ae(0uU9->2_)1x*E|)cX5OMIhdvkSNOA#ld@XMkn?4 z_dMS^xWn>VbNDhTvRw*XF!?{DR(@3rEkASRZ>LG}Px){qB^y?tPMaA#jpuxo%92D$ zSz&g`N7X-4^CV9YvoSR`WkDWjUgqtM#b_wke~zfGJzaJF`GF5#SW zSTniTj8R2BdlKuv=Fr2;8XroH`+cdDVNUu<)l991XE+>#p$svohEm8-Pqrhk-Ow@U zxSQx}uu-E0bTY(PE<+DXro|b?QK(l*43)?d>h!?CmLT}=+kydC*vi`GM@XvVC&XVV zyWvfn2BiuUU2=J{B%|a7HZxjc5?h#~B`&7c8rYG{8zD>)@!gOw$v;5jWIh-@cLE&B z7)hy3RFhFONj_2(djC`;(jrdJk#}LyFTW>F%a#92w*Qf7Fik2wwIvJs55ECXmY$rEOpK$c=yArh<{wb1FHRPC3mf*CnV&P&17GYczN{+nT;# zb-_Ta1401iJfJCTI;JA0?@^yR9f{187# z^K5{fI(I|RB8M`}LbJ@3KX3&{eJH-gv_70?KT$IzS6SSFx|L6>V`(3O&e{VtW`&V* zBX8#hPMO08CHcLPJleO+l|RtJJ=88qvh_84cX(8;I#M zD@XoDEXtA9BD9OnAv)9u_Q<xZr^Bc|XhVy%^m9d_r_q2~s6)Mj?R4OT6(d=1Z7+>Q6IwsaJenF+ z1~uz_Obm@{x4GoET|uXuK5Qv?Ymhf=y~X>Fcg!o8=r>2rC2Qgj7u( z8+o%9PNvP3f2Pqi2MVC?$p68fo?PXU(qLPMQ1;n+%LTR+Cn|6l)ncMytZlFrf+fAV z=YK7YkKoBEH}~AlYUd$PsFf=)uLYK;36_TC09ap;FpMPvm<<4NnRv`6=9B&_&mYK1 zKP=C(VdTKFH58!!-i(zW{Q#(ttK5->MuVrVz2j(5${hd~TSfU0 z#fffb>K7>ZD7O>enTpHSUwxgiEjQ4S1WXHoiL_<}M=~?6WlLsO1KQ(2baV-eY)QSIEtg$3i6(%c2y=JD zFIg%DzK`>X;$|8Th!0tkh;3hVr{!_lILnr?$?9=h%=c^|8@UDllw5RhXrGoF_#we( za@i00_hQ!nkv30b`tM#g3dD;VvEl|P7!XpB+!5&^2pfNjfXOocU^r zNR%xtPpQhxLrZa?PxuCjY&>__huQpNq&PG^G436XVLA)Lx_+1qW{0ks=!0qMA5?0{ zpcQZE=und2Ac3X5MXSIDnxl91lS`jmInvKQaqA(T^1$ z8ME1msaP3nljLp8@ajqU9K<&w@z@{O-^sCzedl<_+25D-CFpG30y+BFTO-Pa( zdEb99ge4B_>$DZ-l^$bUn3Ld3Is4qWozAg^LZ1EW+Us%yk@(!;^f>97JyPKFpQOOH z1SxfIWRDcLeZx(X{L$HekX0}E@S!PRf1{2KG=4dliuD&sY_NDd`Wdv zU`xajq6zVE@<4(*5(5^SSOKpDOzRy>2x}Pf5XEW0&!|@{%jB=Hsk;xIhM0~c6qUuS z1+aCK%jQ(S`a6jGRWKE*0RzX>|2+-z#4uH6Nx$zn=NXy;q}x#tb(r>Z`vw_pUv@J%yO#Fvhlh;=6B_E1Nn zVkEwxG)ZzeOnWGl_$zhV7swk!bU36<_B5IMu7Q}dwBV4GThzIX1*@=JRA@^srV#l< zrLQ)ID68txd>Z$QmPrTXzM_)IA9EV_h;pJ+c}PO6uUs+p!G=+^cUx{z)+PcP7fhO% z+A7N36w~QP@ng;1m-o|{m96&X@i;Ftjp`6>-o zkW@+&uvVTP?2b za-2(fCCy>-=V7rk>iwA!w`z8*n}jmqPNH_)Aw6OY+pPR^h4y4u#DKd zIPa|G#%s=smKzf-DPNqm%sy%v@%iH9vz8fq&st{gIb$j8(-VgyXDq|E$#G#T7!FuQ zv@X6H3@u=227^h(X$lxHG*bTlz6#4fwJU!VD-GG9wtT&nxIc>LzgOZ?Tje<5qcq%t z0#gJ6sxW~Uhf9i&)5@x>b%I?hR=mJa#+wNk>!6+raZZL+l(l0ybQuIPjPaQPZp0tj z$QAw}%G%y|wqNDHMtPko(Vp(ND66QlM7v;ltQngzOi8TeNkMlpx@j@rfTHhWv}y8! zQ&Q?F2xCvaiqUd6q*+U?RZ_-zrQk%bG0ke)93u?{EDfXOILUr@xqlc-0pWurWi?4q z?s6)wf4hdPc7yO^Y0uMrBFW>*k&EdzY)3IyP%k6Mtx~v$rAq4_YR|VeR2=@@F!uS1I@qGfa@x zH-P0!U%503`!iri@ zA^o^tV!v-NYOWXOj`DH$I@IG56bG%#d{K(7x}iZATs@i3 z0uCl>P}oag9LDI&+ye6Jv#3DI>y#IE^5@98_V3Rz=0bAl zoj6I3my}mo3i)Fs+D3_<$DBr+JxmXw4WC9LZ0XGMn9?PFEpblO#CxdR04NIu9-0N^ zew$@eo4Ix%vePqA9OUnVw-K4D67mT5fk(!SwUgXPs;4)fi;wg5#0vNxvw)Sa+*nK{ zk&j>x5=wy{*n6~CUYlgC|32Q*unMgJI(?Tfx|KVu^HyHyIT2|Pns3aqtl8PKogRC4 zKKAP0^*FfmvFEMym}PGFXVic70|^=D8;WVo^4c_1pQA+~t*}adhnGc*uyGV@` zWfkctvsN#U!t$Oq7l=-PUYMq_WRq7VgGE_I1Eb8k%cen4OkUNW!KARvI}`SZtE>#9 zzT}iyCz4m$7$o5vHmrsXX@RGHb(pm(bsrscDvs%7+jDBu5nhHAV;MFR7}$}94v)<^ z?Z{{YLEADMe&7qL!dZkbr<`DeE!F+pFO7*k!G@J+0{Mcl*6yvIr_5;0qMzYnE5jEq zw98jk6ssq3?vsn7M|2YO&y8Ma4L`a1A>i?Zi~oX+J7jCVU|8OW*HI{pS2PPB}C#SkQ-#K%A+EQonbm9!%|k_gj>k zRTX6t^<@b&ITj}I*;!ZuPD81gV&*TWo6rH|)+)-djn1)(tH{Uj1WH~yY{0a(kgKs)F>TZeNWQvS{k z=I$y)4OtqtQ=^hw&hI1-jPG(q%#s6S+t8O(Nli4PHSVW_c+-*90O}-c>pSoSr+FO) zl}0wzDx29fS8YAN6a0ejY9+urMS!(?F)dD&8Gr)W&hP9-EXhiMb%y}!1L7!WT(iuO z^E+v;?(3%nSicCc?jUB$j6A>7tVL2Ak^`(`h-2jdYf_9wnVizN->E31fM|KFC76^d z#%&Yr`<9Q$X*le=QF)Y#C$fWbR5O-G7eslRyqg~6ZO+s^!Gu( zBt?YVAPED}luX(PCM%*_!kHrVbz1&o_HYb?3`AMgXFo#YQXKt3W9XPh0}7h+MMFnD zfq@;F7?$1GEbg2@Be?q4v4RlT9hs>Qip5>?*!#b~=spJ@si6RkGwNJqh)r2fIwCYv zT~dCq%64p!14k2AelCz9deF983il$1_~rDB@%iNx#Dsfc1Lcwf^t?Wc$H9O1avH_; zBnQi8dR%YiQ7MSZ3}`1ulL=E5eYkTd^>Gp zwPgynt!FKL1EeLxvj`9O*~JhP2fKl0B|v!+8*K+Lv<*}OWBC(KNdlCSWM@2>U$GpP z0|f-Z5EsomJy6Fmd~p%k_-BkN;znv~m<05BzPRHl$>W^XCNO38qM;gfafQu-SS>ApA z+?MW)6$MBjl5V9W*wj4i{Pm$QA4eLZyn~!-_5n_$_TPmust6A*n63u-M{J_{U5JOUeODJJ+5K%jH- zodKMI=P>QT`!=PT)!-x84lw8DBqgEUCGT`m&sAT?K}Ec2ITUot-=y!S`c$%=2fmcC zvvABok|C}DoJ^)NJX#)u%VSilYC?e((?pi$lvY%hv*RXkp@8Dx7U?jjqpNz3ky#dae8M7NP@4~f*_GTaO1$^b$!`PDiSD~ooRKz}r8M2{{i1L5fc{%B4WpE48QL-^=^1c3TFZ}=SFslaX6~@xtFE!C%$m`0}|o<;4Nz1 z>JE5N<4p=wg}7yi5$Pt>3PziVrb-c`*?vi0AsC8UiM}nI$H_8I*`V&DrjKGY8cdKu$x+}dMyoYVA53gk5KY4@2@$)=l#3Qf)5LV zKs`7xj9XDA)F19$6nWW%6P_q38))u=GTXtV{%apBmrW~&7A^rR2mcntK8INNM{&g@ zMLqZdCbByMn+r)C4a-l|k%-2_{&4sM$_PF$0!C_|{AM=BzcMh;wNQFkM?8c>X6ZC*Xk8Fe~58Lwrr&cgMpcDFg2AjN#>cS_B zTHIS62Nyp`eGqqtu&+6~0Kukr-|2lD6+>c9bM_>|2OM0UNZSp`CGEK+NRsi+a#DI9n?#b>ce2~9jwj0ncAy;>uoI&s{ovREb5o1d7YoJ%APfnRYj-S# zNPjBrN)jY^f$zd{7=uhQ=KchD=b0Uu+eO`t0U~UNU8a)~;IT;d$Lpa#Rt!p3UHAmm z(oPJVw5U)_sf>%w`S(#1BIPbR)m}&D3G7HLYMJ&1E@;BkD^F0hqT;{1_aYPUyG&#S zIE|%XCC*;Z{FA97&;Aob`Ny{+6_DbDde$+#yy8(p>K2J;%9e(&!7K$fg8>F_Y$ZxQ zLS0$)lFIfLw$5KnXTqt?sD=BWf>dgH2&GVN@2}*i8BU$1mB;m>VY!b7u@P?;ZV8M8 z`vL*;sC$8+?tBjt6~}EP0((D6W<3@M;V{c+0+mGdW-2`lb_Q0Z+%deHZbi)_T@S{R zranZq*V%r)S%&tr%mC4{4%~+bcd{Id>ex#u)VZix8#@A zH7owK)NQCnbu|_plCqiFL-=j-xro!Tn!7_}*Mpc5(od3Zjy3mSDbi;-m3j{iVscB4 z{GA-aT1hV&rx?%Kd3;9sw98-k1#Y@;myAO#q3^R~kK4zXi z|5(aur-cI8!>pLrLp7s;%>O~oC=j%M3S4RmG;V-jG5w^|@>-j6rFdD=3vQh9(7fNL zh~z}x<|_lFSO}V5LsheoZsrUr@KXYgcC~i@w_lWV)4NgSq!~qhWe@HH-jfpN?_Ly& zM@_S>29BUGQ0=Cn=~A=q-F$n>x2jz;@F7eg>apEaCT*&w`JP`KBu{~_r#`h04{R={ z7Uj1oN+KSVM`_bb>rDBG^0FDvPQL9{-E`A{uLIa^FZ3Z=6R6XnD&KzdUGYV_1Ti5g zj)_pGXyN{!LsOtqQOi_J%{Um3Z0(DT)t|`pk!E)Id6ONDx>@~jIJND-`}}lM{Q(?} z%_~k8Vgl~-)e`LDBFk~?Hl+^RNB;F z$MW?4e57Re)KIo6WO>odj2Tp&f$mKHocL~3Z;pwi7EPw;IO>31{KQl-4Ivm~7Tn-j zbu>7fkxFqVYzy_#^uy{NSb?3h;<(X{#LHb$DO}v!q~KCGz4!R6(!%$9JC&IUQe4Ps zpON6l+1gaI(>}%QyB02|@JG_Z=H8Oh3zrV!R7o}~6V0+@j_i~I+k1y!z!5C=JnD-( zaU?wpu15P8mIscojGYQ-Xx*@wR?`QascrUy%ZJfX=+$&jNLc~1M*QEZ3OoAEsSEd3 z>uE12o2DW~q$Rw?70g3X_tOOd`vJ>?Cm@y`ZG3?T(Xurif4SZ8H6;OGV)q>T(R-8Z zORRp2eX`Bp%RW8DZ?aDq=DWcuPfzAIuH+?YGA@8kMm^c&>6!BM6nVl}dBQL?o$Xpy zzRn6ee~|1w=ti~aF{D+pk^{|Y zt4)K;A@ljY)Oh{V5ce=;1v{CQxK5z-8$&FAAq_E5^??DN^rA7E}s{7lhWy?+Yh2!O{wI9z+i0_7gB z`ZRn6bP*bBRAs>9S`^z=yh_V2iovdeTEjrT;9ue8Z)RYDMmLLS0uTM}4A#HTD)3=B z@*o1Hx-5P|)+W?79S6!2vcg-~fn>y21eP1YqD;q7yyhcXi%9|6yp6+AHT+YFeKy{V zL?d=D?s3*qI3Y2daMm(w+Zjt@KVK&KuV(I^XBn|?NfN&MEC8~k7kpY15<^88NZFw$ z_WL!k%6>(Nn~j>=yK z=0IJ6;P0iFnxOglgW-PZ`vY}_0{j#S{ys|9u%RZZcTA)hFHCD#4LI&ZGPpRIOP4m$ z?`|h)QGU#gs23RI8sddJGxQj`FU20{@UZvl-)yOuclY0iQ;^j=IW z{qljaHz@e46Oi{g)~)LE=z2<^5b3Z!l8@{PkVyOo4|N#=zChf?7&z)epiPwW%Mu9O z9UZ24t%{VQxNYhq==pQHTIRjTLo6%`c~CAI;~%4%)HI`Ug=s|VpMEbB=SC}wcZ?_1 z`a-qzX5~?GvqLqRsittX6e~dG$_ztKMjWdyH-&g zMf1x83Oh`5@^fQ#B8&k;7enj}T*+yc88?tgKtk`qXF-i|3IGQHYV7C}sgh!*8Edfo zp)}@!^VIg~MZiS3E6D?lJ@gvpt_)umI1?wcH2$_OUuJ{m%S=;CXuJv3!9OJL@^zmX znvMJlLnFe>n-Vx7UDUQSb+;=vBm4b5aI^a_$QTD661LQA!^qt4|018Cd_aip z_2G^zu6+r2Q2UJ8?KPJ}>a z4v9NKGMJx|?s{)sjf%pVv-%@C5C(0ix>x6j#9W;EXHC!-Y{gZ$>A?p1T8S(aU=q45~Y(BzwkO6dbFTF&Vjd@Gn3!%Oq1M zjuI@=$s)LMi5tjp>q{~`#R|#^-KYkh(8_9+N}cd^%Dd1yu9AZ8h%}~hSBDQbs#?P# ze$Onj8{7w<)nIFaLJ9TokKl5!z&kx%a8R<)T%2^J)wGprl(~`8)JK~m z5jOa0gIdt^JudrFAme;^ePO(JtsH~2>ov4}-DZedB&)JfE` z;XmT2RYTWPD#au+G~;fdbnn0s$D$L}Txf#Q&t;?|ybzY!i4@{&EanQ4t|!vD#+dz? zHS`Tr6XDj_AS-^}vp9 z+8l}W+~8?y7ArU7frKlNLVXHjic@~pjC^phmdtSJqsT9zuPUIro$=4oPENA_vmOD? z*JSp9y&L&FLUXYkV7Hd(o{UL^ySE$k{|Gjs7MA*{h$X+$=V@fk8djS6JPNGjpi6(g zi5f8Ux*J(JakZ5ue#PViD|((8RBucOPV{=Ev7R{boDA9buxd(ETQ;#utz@JlgY1h2 z@+riF=?;z#($Lr6WN0!Y9X(k9cKB_v4z8e--W2s2&h!OnTop&9K)26Wq&r11eS$<& z*h<0lJu`ipx{@VuYyuBz`z&&vJ%Z(T1*frE^R_<5_xYHLgMUrthd4*NIfzDtt zZe52-NEtUwsY#KytK!F`uS0@lb>9&<0YV?cH(f~UPRCGEDLB9feb}H(N*L28(jLD`4HJ5$ei-*^;H>h=(LVMBcvtFU`np^yAi5r zucc0hMaWiccA>2uU7kfRnGP1XH!-EE&!b3KdtlYkPlOy=_bPX@g$Fk453yOvE?Iph zZOMxF-HA)d0t=Q=YbndX3Dj@KS*`_!c!k|8TL7J!DTj&3VfGxDZ6S31Za(bPg!d-V zNw*xrvh@RQzfXaqa$lnutbag(c{dA?6+a76ck^NK-<QH@2sarW>7&`B7>)wUQ{K0rn}i7~(XA#yGJHePPOpDa z=H!pZ^ozIOR-Q;kgRmO@5RHA1S!TR!$Pz7~4 zKr!76#nVs9&$IbRdrKL?1K`9O4l_L#@r6i^|425^n%!Z6daD7->>7#8uBY(3DTtut zyVzY0O2@CKXm?Zi%qO!owYuvwjBjfgyYdPXN4?SeAq>^I9bN4~W6Ng+WyZl|GM-B7 zCH$T@x>)6-KxYEQp5?3GlDc@w1P#KhzWN$*nW|7$H0RE79PC4h9q#`CYle8ITALS4 z*RlwGHb`I;IQe9etX_#;%sZksx0(7<3*dbeBOkg_3erT<)V|~SK^<3uQlF&G_gAJT8)Nv}y7&Ev33;Yi6nY&(m=Ea%dQfswq%o#^r1Q^0 zx$edT8h#ee-p1remd5)zPbQOr*LC82{je1bbaeCgfm@Mpg6L-CFIu;Mp4PI_tQUO) zn~gF3mNLQpQq!VR%A~H`HzKf=T_W(q;~3RD0P&u|a)ywx|0TmmapCRFjjsdetZYdy zpW(kRfRQHZMk6{sR!?-?XU`Z%D$u0LDr$;kaqi?-h(dE&&Cnaz;GHss0vr3zq8U&< z^fI!;sS~=}Ft*j8?cjAZ6j>#^DU8&TG6=s%f_+P3H-Cbp%rUEvy+o=8jAG_oidtT3(xeopZZrn&JOv?t}!Bt$7Mv*i%- zdJ^Yrp}o{N#$=o;p|$v1tfjD7MqT`~CT~4J3E}k7t<8)B;k?R-p)eX!#xNjl3ymF+Nh!?z0#Quec^GIs2j_ObpW^4FVXZy zQ@tx0V;};(R}8epqfa~FdZOvX@j)@V&z&Ek`^-N}67RK2V;rvoL~9J(n{tDH5LF`` zvnH_Zq@}T)a$!!v(5&-VV%(bZ<&ZzuM!fsP^m zximih2b}6c+{O*(Yi9|5+%(WlREX^H_PgrEpoi5;8hfd03r?Y^!q{sE+`ECzA9q@) zkKzn3jCtaS`ny9^3YPB;w97P=LKxojMwCE(k|&VtbIScDb>v|}OsgqBOnv-LU+GT- z8q16>mqX@eg(jyS7F7M7n1ki1M9F&^-Zy3iD*vv04^gLturEg1GQ1v;sFdT^pu(Su?tRg@jwY z)WDlnOn1q)(`yF5d{0EOMenYgNOiFZ2;TxfOvPe{=#-D-q24#)r8NejFs zpOC`}?FW=(pJ4Uhk*_RqbzN{!R!HhGI<3RdqL^NqMa9L-B{-a?GMi=~nP&64a`ig+ zP3hL-fN_A;wUm!MU^&uYQ7+;YGyW?FKVr0G>)aK;7}6wpluh-J&5;Q%>QkQQC{O!A zUw`uA@$qF7?lZA`K1Q56f|bYg9-edQ1v+WW#(G%Te|!4L^uw-T#=R0nj5>wJwu$)L z;V;jDV=61&^b+)pYZ2|A)?AMBOq^Qw^8YvVHzbxr8&PLilO1T26KvrzYCPK5TP8rX z@`Q4!>PF1W5IG$p-%3D)I*j#1$7}%U`?t_QrXGC}Ji!5nCu29xkB{v`{kP%uX?W!J z_-+x=MGNfNX8$nU_k$`pQx-=S*xWd^#t%ibuK&q@B~DO!2JT5lwqN^jCmz=c_UXr} zuY~jB2YgG}ld4pRH89t%BItQ2lZ&){@|?wy^w z=49aQ_|SAVXGIMdNgJSj0C!Qedt0cDKJ+Vi%GG#jY2{IRpLI;Zzg@oH;`cYE<1JZP zbYiqmkPBA2aMcwb*Q=f1cl;cv6#z z^0QCC?qvhYKP{j6D5faWGspD1mJBputpBp~!*)|o5V%P$_e;QoY`TDC>Vl(@NY8`5 z#Y(@gNr8+I$xT){Z>g?h{5Qj?}orz<28b4`_6}fU|veEc6zt_YF+f^y1EQ@Q1SlCVEq;oiBv2hI1)@ zqaDyim5s9&wF#Y1-AX+W^I)TboRwAl_`z{KbfcZ4`sUw}Ptb83hi0lkHLA_3?5C(A zg>d90BAx0dHbr4uHTXY)r=Mfj9@KkSBEC~Ur{2cqOvg^fphli&!q=evtIxhb5**JX zMt%LCct#;#{0BR#`?!Om`iW#OC1U|Nz!)ILEnt9;aXvw?zYM(Ao1as%Of7{rRl^c2}BNI%$u*%WH@ z!=>o|?cGV$^>-?sV*q9RS2VJjp%+7xF=X`xhVzX&!8bBrxlQeJgmR*Y_B#-PN#|Oc z1+bEM9St6n%OSw&a1;&2DvrILXW9is!Ouh~YqZ-Qbi`PR)lMNsg2SEnKK#>ZI#%DO zV>nziyN2SNSXohPSKlBM*`hFM)Fuwosf)I(QSg$ewwIR+i`AF-hK<^KQK%J4krwvX ziT0Jyc>*&W9V)ohc&76a^#O=eH{(mmacaKF^oZhY#G3>(uwdzjECQqn9s%oNMq=#4Yq^8;o?>1L+mk2!v)M{B7P=-4HcHgFi6!w_bYK97)jv{Q=VrY znjAO~=>E(d{B9861khPv#tqzyvBpMw8p!yr0F(Fj$lj@9e1k2KF!@aSxyWw1Y*;}}jJ)I6uu+o` zQ(J@OaT|$KS(@gwNX@WdKPty*#fz0_niv7{N;|o9=*LFwA6XutHDtUy6ORuyuymso zH{MUet3S(@#Jk7ZKU(3Xswsqc!SBIAoBuj864inT^O+IKA&e@#M%4Q;_J-%l$Hk#* zn9=0c^9ONG9_X;HxY~(dssc>*?Shxv)8T%HYg>H*EshF^J2j@_e65=qFIBDTR0MBg z(fllbiVbzL$2Dz#`_?TGbBVqM7XuAQmWDdCd+iRI zrEwwkEV?%7RQ^ddM>pwTCap1zm~4>ri+=U~6l1^o92A=Wjbs?DUnN5%-Mzx?Q8+i$ zzhc`;K7%;G=_k>vwm7J*IsS%}u3(uhnROHTjj`|k0wGadWKgII%5-&+Vo=n!sD~8L zvr=YryYTj_-b3i(IaE)FbX;{V#5*0cl=3uZ-0`6}F?Pm%Gt^~El2508B>#N=GmCUS z@bjSMqm<1w25_$hen24;*U*-WaUn4{DpCHgQ+_}7d>8kM?m4O3obtQq6Y@u??{`Hk zPebQW*lh;Yjqtv>2D^WI6 zqftlF>7d>8CRpKX!VVut-)PxoSh7*e9{wyM)Q;06@0Trm;B&w)(X!#Q?YyA-9rK*i ztj3(`SlHuTF~fVE5*-g>a8rr#Aq)1A>5hw33sECl{X7c3L1Pj^mS%O%V6|aVD<*gaR}+OBngBG}L3W z%I+43WE9MiSo-jvL8x~_LazK64b0l`ZjvD={Tz&hQ3ZYDsGT?(i6bw#1Vg|6Zg#Hn zDwRo;-=YSCfMh|D5~NpMf5w!Hj)08mw=9FEr>-O`Y{OKVYsq;B%WgO>Rr=*2b1wa+ zAMQr^#cPFN6Xr`!4z&(OSriU^iS?t-! zbuqo2hg>1cUhICDLHZ5 z;?9fq@0a&-rtX5-SPNKc!%s>KLn<~r$3MnK?YIsxZeNal+wxwRG;?^<5S7O$f&D{^ z>x?MBO3!1K_V-))tB81IwgYdS#+xXjo_zj|6 zjS?UXf`Yxn;=*Z?<1bj9z>vg=`x0psrS@g!Fg=1Oa0DozTNfbUHTvLxXlZp?J+hUD zC$WkpdI^RE3je-^HO@SwLbh`$sp>|*r5_GDtzNzlrVX(6gWZ?bppeNxu&X_hZ+IBF zqmzY=P)LB|z8Ty!#$xl=3_a;8msal>ptk1X$QcM$T5sKs2)6g=+-~dz^u}N$h2F(z z@?OU2_TtA2iL7H}zXIe8#G9*cWZY^AS{bazs;S=^#G}H=K$^O!Gpei{Uhn*_^K9g$ zE`@1wmA6(SQghjSfmJJpyA;IE$h9+F{g-Kr`QsllZqnZ+SC^}+;md_3lEABFq;7;j z>^if_fruptE;?z>Tr|?krvV0bU>DkXJB95-@uo3eI9Kc5L^S$AmbNQ`7ROPNDeN35 zqX#nK%hb+eAoUCG$yqiLB{6NoV%_p7JNyj}-1h4kwJj-fyV za)92Gq8`}HGWB1Eh4(3}*5AaIpSH=`^`bVa3ydbXL`uK^hoL~C0TWZF%T|bc_oFST zcyq^+>auw)scUTYV7H_`$&Lptsn6NgG5UEMISMSPuh^Pd_@=ED;Y9;6w%kzlutd4x zLQ;dR9USZgg@#MK1BQl<#-3;fj4&xpi?*uspJ4Z<(4L+`Y9D?o4|534ch&b0LHEJT z^~>TTqy1NIwIYpL4ixpX4^NG(7%=I^aibSTU9#kRff&J?HKl*^7{b#g^ z7P{N1{r__U`u{Np$$$O)YJp!Z@T&!WwZN|y_|*cxTHya;3&gQ)MEz}^nwsjGVb;=; zs;X+AwX(XT%sQ{S%4eNdQ@zMqRkFx4+IqwFwKwz zENNU(WhJDvq!iza{D9|rSb;n!5|ySz%gI+$Q8gdglv5deLTzbDWy#!1k5IN`(P-HmDc>+3E7g%X)Q0QDy#I=jOJoJb)M42 zUhDO>0(7dV^ppuqwb97kUs-0Q+FHb{l9Fn@-fx||)aR+yH1bzbd8kgR=lV)um)fPZ zKF=bnucl-vOb#`M-*VH<6jB60VfbRfUkkNITLD^&hA+NTSW;3$N{>cPup(^avDW&% z-s&2kmW$S8s=b~nYgt9Dw-R!++N{--?5u#BglPriGw0+NOwFA%L71L5$31m&!Q|}8 zu6!b#Ij)?7oH^5TCpjliC!j#QJ!j7N$=TELg*lUQ3g(E}1-W;0GB7BAn%g~jYC(>Z zbL7v+FUUc{sp5<|`DwqzCcCpIJ9939PtDDlRDhrUo;>M)jhrJ*o;s6rK)*?1o+b-K zK9cK_xl$&reSPz#!qv(^0TMrI^lHV6T;~L!j*60?*-xX>XnFlRyZyH9pPKTqUx&ZT5n0I zXLN1F-5y8!%>woRk|mznY7AF8h8Bxbj*c}1MHlNJI~LJg5HOzw31t z+Lf{o90T|?*SEEI)Cc{IJ+$5Sr$5r?joaRRhdw86i~CLdnCEb)k2n5=%=;segLpppa3s=tl^~>G zv)c@M@RKMtu7eaIOhWh+964@;dl6P5T!2mRD+sqCJcdw3DBxa+gpKo9gk=Z|5x$AA z4&g|67d9YtAl!j)0>Xm`+Y!3qT)hzvnq>%|LHInv%{Z6n5Br}$I2K_#4o&F){OU%y z8sR~ldp(J;H%_rPAgn>S1L0p09z^&N!V?JF5aMkaVJ?ov`y-6U>2oH+kqBJ~??hOP zuo$5ap%39|gr6d8Mp*W*NaS0DKOju&DF_eJQ9HtX9L<*_d=g02cg!?u@9>S*)HX!V_8RbJ*jqpu` ztq6}Htb!9Lp|>C$c?WBFsdXg5#b_gp&}~BfNlcJ;LGxusgz;aJ4zF5QM%5(T)(-AY6}d@5j&= z;rYXnh#BtdL!Y3W2p#Z*jYSxD1o9AOA$%O+KM`&~cmm;WgoE3lFTz;}I}i^1JQ5j| z1mFG9NW_cqYlKfCEQVjO8R0Vsk0DIK)dzDwL3kA5D1XP9ejVvS-5j%Mkm7+$mj5P1+Ye$rW)OvJA#dF?bfPhH#9Y`*{z#Aq1g>r z{ZYWJi@2ePTMLOs7em9T#or_NYx&&F%tfG1t6MV}OzanCGqTU)Zyk8kprZG#V2fLO zXH|^$HIr?v%FP zQ3aD*=fU*U2@$tpvO3sl8e6J`)w>gA=iw+&`oOle)3jCcPmmWAUbEN?t~$}3-*QsK zoiBa!GWeIF?3nQ9vfBm^Br2^+f1QkD{2NdXQ--+&3jw>n3@ZX#25b|suZWcKH7b9n zw2Qt*yQZom>g%gcG|oovmOH!Uq%Po)^mKx>Vh*?trXGRaov>@-$@G6zIs_e9*Wxx@ z?bb9I7dg_8uRwMeWXD-Y_9LVx5oh7xfC(?#n_0-r$9nWj$S=ftQPw6CKhVDwafvoH zNt@c;=>@^Rad$6>x_cI&OLs451X8s)Xi|F?Yy^!6a(}>G(R54$?YJ6;y?gG%Ik42P z$E{iE)*{9}W@1O$x)c1};I{}LKHeI{Xqc)p^}k8O5G;v@XCeD-$et^*#xLF05y(m( zz5)I|@Nb1r zBd}M1eOeG3r#DFhg*Oh~N54EX^CjV}G%@^V?)=DpsoUM)?FX+xc(??U*TDQ3*aZf$ z*f)T^1q@9wm&m;Y>-F-a)X8V8)kbOk>W$m_`(GP)p=7={REhY{bI*@B!&9 zQVyXqB@@7;^g(dcmcoG3Qb?|VSSQL1pv*l|W_76yB0rc#nYR6IP2_+(zg28CAuVk_ z08y#$R+Qb3vfHI>vzrUv>CTt_eE|4JADo$aPH;2F$N+xYl$LU`*LfZMcHyH{sOJ1A zlCJ_kW7o_~ALfIym^R~dHm1!uZFBL|WQ6On;}J#0MjiG`7d*tVhdLC|krJn2;2pr% zOKi>hs2Tb`7Buce6R9H$*)i;?M4!lZffGXVX5aXQW`eHX^9)Ead z=JQBfnRRY>vm0%7J6qjYtJ~Y^4n*8syBp5CHE6&1?NyXnggu#w8Q7Z)rZG)6$~5Wh z1pgiI&jWu_0?5o`?WK9_82|JJzw8b)xw%evpwaCOe$yT3aC1Fkw0A((%lxU zIxjHmSQ$&QCp`^&#B-3gzPY;O^F!dB4qlQxS)Rlw*K;&x&wy-Ey-o-pVeko$9yGd^xZ0N!o7t{IT*d;73&y}r~A zY!@c0+T1+>IP|GNi@Ptd(tSSA?!FXgc3%lJx`zUt!n|v?jmw~CH}u^8D1K5dcFFl(Bb|7HJxemi#mun|Q&p(h1Br%QXG=a@Ag#U`r}wZXg_Lr^rDplEkH$J`hK zrd_iGX5BzF%k~9PsN4hn@5g@s2-0)vM?EL2yP&^l6eismdhA$j(s%Db*W=J-wt}Yb z*623E^zGT$2s{k_55$(?2Va0dR0fcY;mg2J;D<71JqCXqK_PQ+5AaFgZBh=GU<1JR z0=vQ>xQ79~5!g?FJuP#Gr%$mfuzSIWgO!~MQHlAdP`39;j9sKzw@*n-ir$yO`&;lv zg@^TUO7?=2vKI_)ka?SPaM{dl=U~xWgZrPrQ@9_HvZl?WW-JNsLh#N3?|k8zbv9-hqmmw+lX0>0R znd#!#nG9y!TAAO6-P%r!FwG$6NzZLih z(y&((>@O8FWB-hkac>I#&xH>kOv&D35_|OC;7@eSh@Q(JcOUK<+bM^AsI3#?Lt=F! z_|JoXImg0Xvi~jLlbbzNv+Su>x_g3Er}->Ew?fx$==wVDOMk_=`j~NL;=T>D2)1^w z1hSY$8r>uKdovJ}xn(856u{sF63qZsgI)_@EocP!s=o^$)db{PBJnwfpz+@_+|!y0y_Zg5dmUu?OHd~VTuK> zE7dpz);!#6uf)B3zsR9aZs1%my8)T#i-7AOvlTM`DgHMxVfI3p$AiIL7*q%&RHo&m zs_g;yso=-leZf_r8$f$NuLkWVy%Drgisj1oP!mXFL>U!vZJNyc)3EE}yx>WstuI!& z;fx!-%I%Ekx{p;E>pr?!7Ji7;;qMicy94DCQVw&=RxHK3f5ti?&NDZbVX)`ntl$~Q z#=Lu&hTvQ7ifd)r6Ia|+R^Q++wUQ_=b3+t54&r>`B8hdg*Og^@zS%pa!22oAEM5c4 z3BKsota9f|nHzyWiZcu|KVYwj@zWzw5C%`qGu{U8S-C;G3Zubqxjk?R zMDPu6&06A@0sk=YO9fB3HK@Fqe|vy$1pbWRU8VV>6_&mzKJ=S^WzOA(vag}+AlqGj z--b$^3t9DdKTY3$~p9G(mPk zWDyKl7!bX3H(p;PvllW`A_L!`4^!nrQm+(bYG0(k zaj!FlP&M;uC@ABR?yzgYHps4r>{8JecWdO1@Ma|C94ZfdBj-QPrL%i^1Ss#h+uZ43 zaIL#LxEiBuHAY)IMjvikv1!>IyargO8G#n7dL#gJRTqJVHjb@^EssL9A?%v>#lMe)|;J%+}i1E20mg#W?AWj z3vo8*+<-Gc?3>=T?R%=K9-QYsRn_V4!^z0=_h%16Vh( zwZsa*s8_rP%v9QVL+5BxvyK$mUfo+~Z=_!E}ioVN56%-bBkBgFiYq9T=a z$|GOSl_Q%OT!P*1CkLT&x$^Ro-p+FOkba)@KGH9fK1BLe(!V5qob*XjuYPa-Zwr;k z`P(b=-~Q9eyyj|d)l?CqECLAIhct_j~dmU>?Wz_6l2qBWZJmAF|Y(Qy`i9 zN1H#(5=T!h7BN3gzI^T=m-65G-ORA$_sO{!E_~!|t|K_(l#A7Nj*yR!hRn5^^}|OY z=8|(2x$w2Aii^dZBR{sV9DB(XW5F|Q)}cDbe3k}mMV)0RK28H#?|rPF93{!6_Wx_f zwg-?A{T=fwD1hN*+N*xYSGr7oISs$f{QXAj|J{GnKbqV2^038QN!O9~la7*3k?tVf zMY@;t0O>)}!=y(^t0RuN&Lmw-x}3C?bRB6w=_u(G=?>CeqD+HleUtsBkd<0C7mMO zLAr}{FX;i&gQSN^kCIk5(?029(&ePBr0YogNk>ViNOzF#BHc@Rfb<~gVbY_d)h)D7 zx|no1X)EbE(tgrW(kap%q`OG>k{%#ENP3v`C~0*o?UODhT~69cx{kD;bd+?8bO-4! z(!HbyNDq=8COt}8-A4PQi%FN0wvw(R?I#^2og&>qx{Gu#snzcP|B=@%uK^@bCZ=hn zHCxJDyf!V!1cYH8%9RUzx-$A9Ge!tmf!B-3s0_;C62a#AKM=$ z{$8_7!*?n@{!xCBau3|Z1c~ymWB$jVwF#}S^37+9U@2esh04#^V$LM>d&`e__}=mZ z6@=xPCxT|{>tXBV}6?XA?CL+pJ#px^P|k)%Dme1QZ27~cT!%xRg0 z=(U0>e=au6qJR2V7T5W-k@9y^Ufs|^T;p5MX|4nwKr4R3e%E$gMfvBc=hMi`mBgRe z?S0c^OXpSt#A6;@4s)dbD-%}!OO`mFA^r>E4a7f7{H#6;TtNJO;w{9{d~!cG*pv^UK5hKR4B{B68J(*D{&{0ZXbHz_D1?J$1x z`2W5I79aQE{gj`kUGa-tS>ie38n=0azt0K1YUMgDamFZL^vK@;T-y7`=F}0taYkOQ zN#fV#Z2lZeoUO!fAa&9^*-n;#MfVM1rwBi!suD#biQc; zjVpO8gVggW%Ij_ZGsM^Bt-SeN3X)F+tv_$}wD-HzzlHj1Y4>I7(a#Uq{my%go`p{D zKU={qtk5s0r`MzZN7SRAx7ZC=OG9}(Y7T#tvA5r2&M6}FfY zA^z{g&2K-z>maV@5tEef0xt8do?kF5oU4iJ`irc&Qq=RI8*QG=cCto(k+YBeI6(O# z$xgbIW$#r2O!wETHq}JHP|@CBZY?PsqA1S5+0q z5#`NqIe;%D{?@0Bm}7pIf#e5)%X~HM87~)6UO%^5Zi_jW5^187E^+-FQse4}z>S~(%?i$^{2|Kg z=a|n1EaM&GdcUCK@n4ARK41MW{VDOI_Xn3y|54(4UvVk%z&tCjpI1IZ{8ZxA_gKJu zuOG=p#P##fjg((ZTt6S3Aij*ao;NiTznr+9<4qB7BwoYwA3cv;NnFo;^gjPe;(DHI zzGn|z*8n%`)T>r;i2h7dUeAxs_u(OOI`KEAt-SdjJCeiHvybO|otEv4P+mXx{T%Tv zMjrDO`UWrwv}?=>5=Xtj}}A_5MZc^CEG*zft@ji0l1~;;#|c`yR#rg}B}qDSj0A zT=y^U0GBvl&}A#A>)J^t*!ggP^C7b4I-U5S2R{qASx>2_k#SN-{4?FQ{6*BWlzPI{ zQ%C$G#2pVF0X|p#rPy3}6!LgdiF1T{Bq!I^Mt^PT^K6Ua84m_O)A4?8`*k=lg!T8( z>ndsK$04tMTF$xM2mgW({-_VW-v|GW5B_~0{3ky6Q6GFk_1x|HCj4+3;-uzE+ge>; z&h(N0Lm&K7AH2ihuJgcJtDoC1=V~AMf)D;lAN;exL**UC^t6xs<39MaKKMZ&{B^;D zr#Sk353Rz_jJ)f7nG^pKGJfZy=e^jF%oT4TAAE@q-sFR?^TCro_>d2NqYr+Y4}Px? z{)E9@=P}M3)AY}`eB}S$2bbUfhgi0pyyGK(D&qW9`9} zc&87Z@WFFFINnq=XFS~IgMSftsI1akcaSr-BSgITdsN}eA!*LYd)gZKO3MIZcAKKNY*cb%`Wo*!h5 zb`n3I?LCqBE+0K#^TEI2gMZHl|B(-V#0P&1_^H8#&KB;Y)S&@XSo-U>^%gPD2}1Hj zgR9gmJ;w)c051CV`w?2=a_aA*-)P2(`smrhALY_aL%l1~CB;y+A&z^of1^8U;4f)`Ueee(a;LSex z8Xx>RAAHOQzr_c?*Wj+x!2QG7^ut$)pZ|~ra6)9R$BCcDK;v=V56$q^s{#mM6vhWq3e_Sf(E z=(*4bZ}-7_sQ0i6AF`cKCyT{lJT6zB6AX>%tfWVBDLg%#dw2x>kj$nNLnAqXU@1R5 zT+9{oj!^5TS(m~R#7FW4JhFXrdLjqq1@nYvs9>#!Mh4}1(}RfuIx(N<>l;A_p=%_K zA`nLu;Azx&q<-ya* zLC8zO)NrVOI5|>4q`+0PPO8Vl>x=ab>NA8$aZ@5Ep;8>|Pb7;@W+*v?+Ri@dTHFb4 z|424lfV1$_W%~r|emvH`C{K0=)4ERFB|gvPhja4y?Sf4;u)4)e5pLm=n+xfoRC*L~ zG>0Gq&KWlqw~?c9!B|F{(6;nAoB>~Tp+R&P zp8GD<7E7ku6tHIOQ|*frxwIq9biO#jelnJ9Bn_hHhUEnU(tq$g)Z0$B;b5JG_@moK zGwHF}aAz?*NZdR*U!EwQ$Pr8-RP)0X7Nui9K8)TJ_elnNg;*aA4v)Yae3Cw@GK#Pk zBtMc(n?O@1jwR}snCFHgdgXls1&k!TI3T%Mh9Y`?P$Fq0H#(ek@KpaHq4J<}lb86C zM~+L$IHGuBNh!6|q>>W}8PArvtdznd_w!?z^hS#PD^h8BsenASU$SOwfSUZc=#JY# z>DWv^g3idHaz=a{B$I`%cpTp$iMK@KtzCF1eLUKX2g0{?tZ9sN#MiX8cH`msJ(0$a zmbepdz6y`6Z*Ov1lTCQ@L3g?sNu?wOpwqs(q1k%diDib;`NUx2%8_(_qT2*~!HG4Q zS)vtnYqG;V)+)7%t%8%+n|B{L1|hdFl*4-#iv8iXj`qf;_{I2+%Ow(~g-ogfiuD(b z&a8y-Y*j{b*^IpK0dWdOWr-&9SbI#VGz+iB3&}xsS*$A!e-#EkmY(PvPUKUo?DXQq z+A!gCr}LwDf_7~VP>7nPCmxqDiX))$fc!YdmArnT!ftvzQ>*}DaAK2G zuNe`t3f<|%x)Pa!Rx9408OlhP$E8Ej^f*SDUAtmyhh+Ba9ENGFjd5Wo$Cz~`bjmw1 zP|2JFKQ&`!?>29*Sc?cUi&A>9vPROxl2&U3Zg6Z(6NQ4bRlAbjE5(EDU?(=%*Mk{M zYtl0;xsFT$%N?4+uw*oJ3n(p%HIi1LvnQLvf7P6l!c=Hc{v>@1Bt6OR%<#LtVk?&y5t56)l$$QUTCkrI>CS z&P_xR!cMF?olO_h+CHq2`D}WqqO7U>oK=sowBVh2!BRq5H*VbnE0JTe5gwPN1y!WIa- z0jxAJjPah~?!;&sVh*AX_Ovb-0ZmyA2@|Csiw#8OXhoCy3I&Ez zY2rhNH4bC3iFHp5B~5Xw4(schF-*&tZ)e-kjU~`FCoX!Do8!rW&2f2MOsNISoY;D7 zm`Zbk?G72KrYZ1za z&oB~&i9s7u-DVaulZq}j?S)9Pm>I=ZW+2mFG+P9W9>jc_3yQ5prSkrw47Zl?B0{ZT zCPkUpb=pK1%f8Zy!%a@CU8dThh-?H=&!J-~YF4{B{KUo4v;++>4Urbv^`y~kX6<@n z25?!-ax8K7H~vdz^E!oMvcnxlMSCz6o23o2K>=Gud9e!ORyOvf*~%m^ijZHLEaR^~wh?-Q0#M3fU>RQ8kA$W6Ui9~Y_}FQjx~?i)7zy#0L_%H?B`j49PGu6!&C?gB?u)6GTNO4qiT;O^6^yIz|J567 zRx{=~2RAu`*f_&Q|0~y7&=SC3klJeTeHgiv>ba{$t*oYnegJM509!SYJO;FVu` zKBw4nB+AQ=v%J#tRFG6Zzf-u~Q~nDquQa5Bq~7v!TznM2G1vC*V|k@&A0OkI%Uk~h zP#g`H+ONOMSL)#CM=oij_*u)>3WzI%KQXEH^>_YC^>_UuE0^dfzph6Hztt+$Uw=2R zR10YR)s9m6TAutSU-SCAe5GL;^VXlRa|aUQQ!TI01yHKb1yK9m_TR(ujZ~=58BnUv zC6MysGjI7X0TZ97ekY8KTw(LSBk^5+dHeqhV3wB;g{`#GX=!-brQa)3`Ve^K<@Nke z=_mMoepR96H2)W#^7_33r8su2xV-g$oaKWm#m~9*^X?<~UP$>BD$gMOH2$RiT3)|j zqx1oe2QB8c{~b^HZC|&NN{^hbB`wwdQ}pkVz|p1|1A^&uGn9JeHLvu?D050#d3~;i zQk4_ka%o=aFMvt=wVC?;ZKWY~j1 z8iY$}oz0g1*YZlMJ>~Ve9!d{s#i&8cDLutgUcVQmbXq32vMW@UmgM_TUUaD${X9Ww zoibQ1M5<&F?Kdbus^z`o7vknBr=Bh{{AqqpdWZ{{e6M*2{jx5?WtZAj=u{-;D!=|LD=ELfD8D>e=YIgrj!72) literal 0 HcmV?d00001 diff --git a/stuff/manual-programs/suckless/dwm-bak/dwm-autostart-20161205-bb3bd6f.diff b/stuff/manual-programs/suckless/dwm-bak/dwm-autostart-20161205-bb3bd6f.diff new file mode 100644 index 0000000..6f11eaf --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/dwm-autostart-20161205-bb3bd6f.diff @@ -0,0 +1,39 @@ +commit 5918623c5bd7fda155bf9dc3d33890c4ae1722d0 +Author: Simon Bremer +Date: Thu Dec 22 17:31:07 2016 +0100 + + Applied and fixed autostart patch for previous version; + +diff --git a/dwm.c b/dwm.c +index d27cb67..066ed71 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -194,6 +194,7 @@ static void resizeclient(Client *c, int x, int y, int w, int h); + static void resizemouse(const Arg *arg); + static void restack(Monitor *m); + static void run(void); ++static void runAutostart(void); + static void scan(void); + static int sendevent(Client *c, Atom proto); + static void sendmon(Client *c, Monitor *m); +@@ -1386,6 +1387,12 @@ run(void) + } + + void ++runAutostart(void) { ++ system("cd ~/.dwm; ./autostart_blocking.sh"); ++ system("cd ~/.dwm; ./autostart.sh &"); ++} ++ ++void + scan(void) + { + unsigned int i, num; +@@ -2145,6 +2152,7 @@ main(int argc, char *argv[]) + checkotherwm(); + setup(); + scan(); ++ runAutostart(); + run(); + cleanup(); + XCloseDisplay(dpy); diff --git a/stuff/manual-programs/suckless/dwm-bak/dwm-fullgaps-6.2.diff b/stuff/manual-programs/suckless/dwm-bak/dwm-fullgaps-6.2.diff new file mode 100644 index 0000000..7206aec --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/dwm-fullgaps-6.2.diff @@ -0,0 +1,95 @@ +diff --git a/config.def.h b/config.def.h +index 1c0b587..38d2f6c 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 = 5; /* gaps between windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ +@@ -84,6 +85,9 @@ static Key keys[] = { + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, ++ { MODKEY, XK_minus, setgaps, {.i = -1 } }, ++ { MODKEY, XK_equal, setgaps, {.i = +1 } }, ++ { MODKEY|ShiftMask, XK_equal, setgaps, {.i = 0 } }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) +diff --git a/dwm.c b/dwm.c +index 4465af1..4363627 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -119,6 +119,7 @@ struct Monitor { + int by; /* bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ ++ int gappx; /* gaps between windows */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; +@@ -199,6 +200,7 @@ static void sendmon(Client *c, Monitor *m); + static void setclientstate(Client *c, long state); + static void setfocus(Client *c); + static void setfullscreen(Client *c, int fullscreen); ++static void setgaps(const Arg *arg); + static void setlayout(const Arg *arg); + static void setmfact(const Arg *arg); + static void setup(void); +@@ -638,6 +640,7 @@ createmon(void) + m->nmaster = nmaster; + m->showbar = showbar; + m->topbar = topbar; ++ m->gappx = gappx; + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); +@@ -1497,6 +1500,16 @@ setfullscreen(Client *c, int fullscreen) + } + } + ++void ++setgaps(const Arg *arg) ++{ ++ if ((arg->i == 0) || (selmon->gappx + arg->i < 0)) ++ selmon->gappx = 0; ++ else ++ selmon->gappx += arg->i; ++ arrange(selmon); ++} ++ + void + setlayout(const Arg *arg) + { +@@ -1683,16 +1696,16 @@ tile(Monitor *m) + if (n > m->nmaster) + mw = m->nmaster ? m->ww * m->mfact : 0; + else +- mw = m->ww; +- for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ mw = m->ww - m->gappx; ++ for (i = 0, my = ty = m->gappx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { +- h = (m->wh - my) / (MIN(n, m->nmaster) - i); +- resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); +- my += HEIGHT(c); ++ h = (m->wh - my) / (MIN(n, m->nmaster) - i) - m->gappx; ++ resize(c, m->wx + m->gappx, m->wy + my, mw - (2*c->bw) - m->gappx, h - (2*c->bw), 0); ++ my += HEIGHT(c) + m->gappx; + } 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); +- ty += HEIGHT(c); ++ h = (m->wh - ty) / (n - i) - m->gappx; ++ resize(c, m->wx + mw + m->gappx, m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->gappx, h - (2*c->bw), 0); ++ ty += HEIGHT(c) + m->gappx; + } + } + +-- +2.20.1 + diff --git a/stuff/manual-programs/suckless/dwm-bak/dwm-systray-6.2.diff b/stuff/manual-programs/suckless/dwm-bak/dwm-systray-6.2.diff new file mode 100644 index 0000000..27187ac --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/dwm-systray-6.2.diff @@ -0,0 +1,746 @@ +From 4001ccae7b1a41bdcb247b0cf095a51af7b68c28 Mon Sep 17 00:00:00 2001 +From: Igor Gevka +Date: Sun, 16 Feb 2020 15:03:10 -0800 +Subject: [PATCH] [PATCH] Implements a system tray for dwm. + +Original author: Jan Christoph Ebersbach , inspired by http://code.google.com/p/dwm-plus +URL: http://dwm.suckless.org/patches/systray +dwm 6.2 port by Igor Gevka +--- + config.def.h | 4 + + dwm.c | 404 +++++++++++++++++++++++++++++++++++++++++++++++---- + 2 files changed, 382 insertions(+), 26 deletions(-) + +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 4465af1..3e361fa 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); +@@ -169,8 +193,10 @@ static void focus(Client *c); + static void focusin(XEvent *e); + static void focusmon(const Arg *arg); + static void focusstack(const Arg *arg); ++static Atom getatomprop(Client *c, Atom prop); + static int getrootptr(int *x, int *y); + static long getstate(Window w); ++static 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); +@@ -188,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); +@@ -206,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 *); +@@ -223,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; +@@ -257,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; +@@ -439,7 +475,7 @@ buttonpress(XEvent *e) + arg.ui = 1 << i; + } else if (ev->x < x + blw) + click = ClkLtSymbol; +- else if (ev->x > selmon->ww - TEXTW(stext)) ++ else if (ev->x > selmon->ww - TEXTW(stext) - getsystraywidth()) + click = ClkStatusText; + else + click = ClkWinTitle; +@@ -482,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++) +@@ -512,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]) { +@@ -567,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); +@@ -652,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 +@@ -695,19 +789,23 @@ dirtomon(int dir) + void + drawbar(Monitor *m) + { +- int x, w, sw = 0; ++ int x, w, sw = 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]); +- sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ +- drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0); ++ sw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ ++ drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0); + } + ++ resizebarwin(m); + for (c = m->clients; c; c = c->next) { + occ |= c->tags; + if (c->isurgent) +@@ -728,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 - sw - x) > bh) { ++ if ((w = m->ww - sw - 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); +@@ -739,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 +@@ -776,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 +@@ -862,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; +@@ -899,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) + { +@@ -1003,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); +@@ -1091,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; +@@ -1215,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) +@@ -1265,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) + { +@@ -1272,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) + { +@@ -1344,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) + { +@@ -1433,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; + } +@@ -1466,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 +@@ -1555,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); +@@ -1562,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); +@@ -1570,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(); +@@ -1701,7 +1889,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); + } + +@@ -1796,11 +1995,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, +@@ -1811,10 +2017,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); + } +@@ -1990,6 +2201,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 +@@ -2057,6 +2383,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) + { +@@ -2110,6 +2446,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) + { +-- +2.17.1 + diff --git a/stuff/manual-programs/suckless/dwm-bak/dwm.1 b/stuff/manual-programs/suckless/dwm-bak/dwm.1 new file mode 100644 index 0000000..13b3729 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/dwm.1 @@ -0,0 +1,176 @@ +.TH DWM 1 dwm\-VERSION +.SH NAME +dwm \- dynamic window manager +.SH SYNOPSIS +.B dwm +.RB [ \-v ] +.SH DESCRIPTION +dwm is a dynamic window manager for X. It manages windows in tiled, monocle +and floating layouts. Either layout can be applied dynamically, optimising the +environment for the application in use and the task performed. +.P +In tiled layouts windows are managed in a master and stacking area. The master +area on the left contains one window by default, and the stacking area on the +right contains all other windows. The number of master area windows can be +adjusted from zero to an arbitrary number. In monocle layout all windows are +maximised to the screen size. In floating layout windows can be resized and +moved freely. Dialog windows are always managed floating, regardless of the +layout applied. +.P +Windows are grouped by tags. Each window can be tagged with one or multiple +tags. Selecting certain tags displays all windows with these tags. +.P +Each screen contains a small status bar which displays all available tags, the +layout, the title of the focused window, and the text read from the root window +name property, if the screen is focused. A floating window is indicated with an +empty square and a maximised floating window is indicated with a filled square +before the windows title. The selected tags are indicated with a different +color. The tags of the focused window are indicated with a filled square in the +top left corner. The tags which are applied to one or more windows are +indicated with an empty square in the top left corner. +.P +dwm draws a small border around windows to indicate the focus state. +.SH OPTIONS +.TP +.B \-v +prints version information to standard output, then exits. +.SH USAGE +.SS Status bar +.TP +.B X root window name +is read and displayed in the status text area. It can be set with the +.BR xsetroot (1) +command. +.TP +.B Button1 +click on a tag label to display all windows with that tag, click on the layout +label toggles between tiled and floating layout. +.TP +.B Button3 +click on a tag label adds/removes all windows with that tag to/from the view. +.TP +.B Mod1\-Button1 +click on a tag label applies that tag to the focused window. +.TP +.B Mod1\-Button3 +click on a tag label adds/removes that tag to/from the focused window. +.SS Keyboard commands +.TP +.B Mod1\-Shift\-Return +Start +.BR st(1). +.TP +.B Mod1\-p +Spawn +.BR dmenu(1) +for launching other programs. +.TP +.B Mod1\-, +Focus previous screen, if any. +.TP +.B Mod1\-. +Focus next screen, if any. +.TP +.B Mod1\-Shift\-, +Send focused window to previous screen, if any. +.TP +.B Mod1\-Shift\-. +Send focused window to next screen, if any. +.TP +.B Mod1\-b +Toggles bar on and off. +.TP +.B Mod1\-t +Sets tiled layout. +.TP +.B Mod1\-f +Sets floating layout. +.TP +.B Mod1\-m +Sets monocle layout. +.TP +.B Mod1\-space +Toggles between current and previous layout. +.TP +.B Mod1\-j +Focus next window. +.TP +.B Mod1\-k +Focus previous window. +.TP +.B Mod1\-i +Increase number of windows in master area. +.TP +.B Mod1\-d +Decrease number of windows in master area. +.TP +.B Mod1\-l +Increase master area size. +.TP +.B Mod1\-h +Decrease master area size. +.TP +.B Mod1\-Return +Zooms/cycles focused window to/from master area (tiled layouts only). +.TP +.B Mod1\-Shift\-c +Close focused window. +.TP +.B Mod1\-Shift\-space +Toggle focused window between tiled and floating state. +.TP +.B Mod1\-Tab +Toggles to the previously selected tags. +.TP +.B Mod1\-Shift\-[1..n] +Apply nth tag to focused window. +.TP +.B Mod1\-Shift\-0 +Apply all tags to focused window. +.TP +.B Mod1\-Control\-Shift\-[1..n] +Add/remove nth tag to/from focused window. +.TP +.B Mod1\-[1..n] +View all windows with nth tag. +.TP +.B Mod1\-0 +View all windows with any tag. +.TP +.B Mod1\-Control\-[1..n] +Add/remove all windows with nth tag to/from the view. +.TP +.B Mod1\-Shift\-q +Quit dwm. +.SS Mouse commands +.TP +.B Mod1\-Button1 +Move focused window while dragging. Tiled windows will be toggled to the floating state. +.TP +.B Mod1\-Button2 +Toggles focused window between floating and tiled state. +.TP +.B Mod1\-Button3 +Resize focused window while dragging. Tiled windows will be toggled to the floating state. +.SH CUSTOMIZATION +dwm is customized by creating a custom config.h and (re)compiling the source +code. This keeps it fast, secure and simple. +.SH SEE ALSO +.BR dmenu (1), +.BR st (1) +.SH ISSUES +Java applications which use the XToolkit/XAWT backend may draw grey windows +only. The XToolkit/XAWT backend breaks ICCCM-compliance in recent JDK 1.5 and early +JDK 1.6 versions, because it assumes a reparenting window manager. Possible workarounds +are using JDK 1.4 (which doesn't contain the XToolkit/XAWT backend) or setting the +environment variable +.BR AWT_TOOLKIT=MToolkit +(to use the older Motif backend instead) or running +.B xprop -root -f _NET_WM_NAME 32a -set _NET_WM_NAME LG3D +or +.B wmname LG3D +(to pretend that a non-reparenting window manager is running that the +XToolkit/XAWT backend can recognize) or when using OpenJDK setting the environment variable +.BR _JAVA_AWT_WM_NONREPARENTING=1 . +.SH BUGS +Send all bug reports with a patch to hackers@suckless.org. diff --git a/stuff/manual-programs/suckless/dwm-bak/dwm.c b/stuff/manual-programs/suckless/dwm-bak/dwm.c new file mode 100644 index 0000000..f4e0d0b --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/dwm.c @@ -0,0 +1,2524 @@ +/* See LICENSE file for copyright and license details. + * + * dynamic window manager is designed like any other X client as well. It is + * driven through handling X events. In contrast to other X clients, a window + * manager selects for SubstructureRedirectMask on the root window, to receive + * events about window (dis-)appearance. Only one X connection at a time is + * allowed to select for this event mask. + * + * The event handlers of dwm are organized in an array which is accessed + * whenever a new event has been fetched. This allows event dispatching + * in O(1) time. + * + * Each child of the root window is called a client, except windows which have + * set the override_redirect flag. Clients are organized in a linked client + * list on each monitor, the focus history is remembered through a stack list + * on each monitor. Each client contains a bit array to indicate the tags of a + * client. + * + * Keys and tagging rules are organized as arrays and defined in config.h. + * + * To understand everything else, start reading main(). + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef XINERAMA +#include +#endif /* XINERAMA */ +#include + +#include "drw.h" +#include "util.h" + +/* macros */ +#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) +#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) +#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ + * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) +#define 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 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 */ + +typedef union { + int i; + unsigned int ui; + float f; + const void *v; +} Arg; + +typedef struct { + unsigned int click; + unsigned int mask; + unsigned int button; + void (*func)(const Arg *arg); + const Arg arg; +} Button; + +typedef struct Monitor Monitor; +typedef struct Client Client; +struct Client { + char name[256]; + float mina, maxa; + int x, y, w, h; + int oldx, oldy, oldw, oldh; + int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int bw, oldbw; + unsigned int tags; + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; + Client *next; + Client *snext; + Monitor *mon; + Window win; +}; + +typedef struct { + unsigned int mod; + KeySym keysym; + void (*func)(const Arg *); + const Arg arg; +} Key; + +typedef struct { + const char *symbol; + void (*arrange)(Monitor *); +} Layout; + +struct Monitor { + char ltsymbol[16]; + float mfact; + int nmaster; + int num; + int by; /* bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ + int gappx; /* gaps between windows */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; + int showbar; + int topbar; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; + const Layout *lt[2]; +}; + +typedef struct { + const char *class; + const char *instance; + const char *title; + unsigned int tags; + int isfloating; + int monitor; +} Rule; + +typedef struct Systray Systray; +struct Systray { + Window win; + Client *icons; +}; + +/* function declarations */ +static void applyrules(Client *c); +static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); +static void arrange(Monitor *m); +static void arrangemon(Monitor *m); +static void attach(Client *c); +static void attachstack(Client *c); +static void buttonpress(XEvent *e); +static void checkotherwm(void); +static void cleanup(void); +static void cleanupmon(Monitor *mon); +static void clientmessage(XEvent *e); +static void configure(Client *c); +static void configurenotify(XEvent *e); +static void configurerequest(XEvent *e); +static Monitor *createmon(void); +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 enternotify(XEvent *e); +static void expose(XEvent *e); +static void focus(Client *c); +static void focusin(XEvent *e); +static void focusmon(const Arg *arg); +static void 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); +static void incnmaster(const Arg *arg); +static void keypress(XEvent *e); +static void killclient(const Arg *arg); +static void manage(Window w, XWindowAttributes *wa); +static void mappingnotify(XEvent *e); +static void maprequest(XEvent *e); +static void monocle(Monitor *m); +static void motionnotify(XEvent *e); +static void movemouse(const Arg *arg); +static Client *nexttiled(Client *c); +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 runAutostart(void); +static void scan(void); +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); +static void setfullscreen(Client *c, int fullscreen); +static void setgaps(const Arg *arg); +static void setlayout(const Arg *arg); +static void setmfact(const Arg *arg); +static void setup(void); +static void seturgent(Client *c, int urg); +static void 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 *); +static void togglebar(const Arg *arg); +static void togglefloating(const Arg *arg); +static void toggletag(const Arg *arg); +static void toggleview(const Arg *arg); +static void unfocus(Client *c, int setfocus); +static void unmanage(Client *c, int destroyed); +static void unmapnotify(XEvent *e); +static void updatebarpos(Monitor *m); +static void updatebars(void); +static void updateclientlist(void); +static 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; +static int sw, sh; /* X display screen geometry width, height */ +static int bh, blw = 0; /* bar geometry */ +static int lrpad; /* sum of left and right padding for text */ +static int (*xerrorxlib)(Display *, XErrorEvent *); +static unsigned int numlockmask = 0; +static void (*handler[LASTEvent]) (XEvent *) = { + [ButtonPress] = buttonpress, + [ClientMessage] = clientmessage, + [ConfigureRequest] = configurerequest, + [ConfigureNotify] = configurenotify, + [DestroyNotify] = destroynotify, + //[EnterNotify] = enternotify, + [Expose] = expose, + [FocusIn] = focusin, + [KeyPress] = keypress, + [MappingNotify] = mappingnotify, + [MapRequest] = maprequest, + [MotionNotify] = motionnotify, + [PropertyNotify] = propertynotify, + [ResizeRequest] = resizerequest, + [UnmapNotify] = unmapnotify +}; +static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; +static int running = 1; +static Cur *cursor[CurLast]; +static Clr **scheme; +static Display *dpy; +static Drw *drw; +static Monitor *mons, *selmon; +static Window root, wmcheckwin; + +/* configuration, allows nested code to access above variables */ +#include "config.h" + +/* compile-time check if all tags fit into an unsigned int bit array. */ +struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +/* function implementations */ +void +applyrules(Client *c) +{ + const char *class, *instance; + unsigned int i; + const Rule *r; + Monitor *m; + XClassHint ch = { NULL, NULL }; + + /* rule matching */ + c->isfloating = 0; + c->tags = 0; + XGetClassHint(dpy, c->win, &ch); + class = ch.res_class ? ch.res_class : broken; + instance = ch.res_name ? ch.res_name : broken; + + for (i = 0; i < LENGTH(rules); i++) { + r = &rules[i]; + if ((!r->title || strstr(c->name, r->title)) + && (!r->class || strstr(class, r->class)) + && (!r->instance || strstr(instance, r->instance))) + { + c->isfloating = r->isfloating; + c->tags |= r->tags; + for (m = mons; m && m->num != r->monitor; m = m->next); + if (m) + c->mon = m; + } + } + if (ch.res_class) + XFree(ch.res_class); + if (ch.res_name) + XFree(ch.res_name); + c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; +} + +int +applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) +{ + int baseismin; + Monitor *m = c->mon; + + /* set minimum possible */ + *w = MAX(1, *w); + *h = MAX(1, *h); + if (interact) { + if (*x > sw) + *x = sw - WIDTH(c); + if (*y > sh) + *y = sh - HEIGHT(c); + if (*x + *w + 2 * c->bw < 0) + *x = 0; + if (*y + *h + 2 * c->bw < 0) + *y = 0; + } else { + if (*x >= m->wx + m->ww) + *x = m->wx + m->ww - WIDTH(c); + if (*y >= m->wy + m->wh) + *y = m->wy + m->wh - HEIGHT(c); + if (*x + *w + 2 * c->bw <= m->wx) + *x = m->wx; + if (*y + *h + 2 * c->bw <= m->wy) + *y = m->wy; + } + if (*h < bh) + *h = bh; + if (*w < bh) + *w = bh; + if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { + /* see last two sentences in ICCCM 4.1.2.3 */ + baseismin = c->basew == c->minw && c->baseh == c->minh; + if (!baseismin) { /* temporarily remove base dimensions */ + *w -= c->basew; + *h -= c->baseh; + } + /* adjust for aspect limits */ + if (c->mina > 0 && c->maxa > 0) { + if (c->maxa < (float)*w / *h) + *w = *h * c->maxa + 0.5; + else if (c->mina < (float)*h / *w) + *h = *w * c->mina + 0.5; + } + if (baseismin) { /* increment calculation requires this */ + *w -= c->basew; + *h -= c->baseh; + } + /* adjust for increment value */ + if (c->incw) + *w -= *w % c->incw; + if (c->inch) + *h -= *h % c->inch; + /* restore base dimensions */ + *w = MAX(*w + c->basew, c->minw); + *h = MAX(*h + c->baseh, c->minh); + if (c->maxw) + *w = MIN(*w, c->maxw); + if (c->maxh) + *h = MIN(*h, c->maxh); + } + return *x != c->x || *y != c->y || *w != c->w || *h != c->h; +} + +void +arrange(Monitor *m) +{ + if (m) + showhide(m->stack); + else for (m = mons; m; m = m->next) + showhide(m->stack); + if (m) { + arrangemon(m); + restack(m); + } else for (m = mons; m; m = m->next) + arrangemon(m); +} + +void +arrangemon(Monitor *m) +{ + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); + if (m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); +} + +void +attach(Client *c) +{ + c->next = c->mon->clients; + c->mon->clients = c; +} + +void +attachstack(Client *c) +{ + c->snext = c->mon->stack; + c->mon->stack = c; +} + +void +buttonpress(XEvent *e) +{ + unsigned int i, x, click; + Arg arg = {0}; + Client *c; + Monitor *m; + XButtonPressedEvent *ev = &e->xbutton; + + click = ClkRootWin; + /* focus monitor if necessary */ + if ((m = wintomon(ev->window)) && m != selmon) { + unfocus(selmon->sel, 1); + selmon = m; + focus(NULL); + } + if (ev->window == selmon->barwin) { + i = x = 0; + 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 - TEXTW(stext) - getsystraywidth()) + click = ClkStatusText; + else + click = ClkWinTitle; + } else if ((c = wintoclient(ev->window))) { + focus(c); + restack(selmon); + XAllowEvents(dpy, ReplayPointer, CurrentTime); + click = ClkClientWin; + } + for (i = 0; i < LENGTH(buttons); i++) + if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button + && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) + buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); +} + +void +checkotherwm(void) +{ + xerrorxlib = XSetErrorHandler(xerrorstart); + /* this causes an error if some other window manager is running */ + XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask); + XSync(dpy, False); + XSetErrorHandler(xerror); + XSync(dpy, False); +} + +void +cleanup(void) +{ + Arg a = {.ui = ~0}; + Layout foo = { "", NULL }; + Monitor *m; + size_t i; + + view(&a); + selmon->lt[selmon->sellt] = &foo; + for (m = mons; m; m = m->next) + while (m->stack) + unmanage(m->stack, 0); + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); + if (showsystray) { + XUnmapWindow(dpy, systray->win); + XDestroyWindow(dpy, systray->win); + free(systray); + } + for (i = 0; i < CurLast; i++) + drw_cur_free(drw, cursor[i]); + for (i = 0; i < LENGTH(colors); i++) + free(scheme[i]); + XDestroyWindow(dpy, wmcheckwin); + drw_free(drw); + XSync(dpy, False); + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); +} + +void +cleanupmon(Monitor *mon) +{ + Monitor *m; + + if (mon == mons) + mons = mons->next; + else { + for (m = mons; m && m->next != mon; m = m->next); + m->next = mon->next; + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); + free(mon); +} + +void +clientmessage(XEvent *e) +{ + XWindowAttributes wa; + XSetWindowAttributes swa; + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); + + if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { + /* add systray icons */ + if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { + if (!(c = (Client *)calloc(1, sizeof(Client)))) + die("fatal: could not malloc() %u bytes\n", sizeof(Client)); + if (!(c->win = cme->data.l[2])) { + free(c); + return; + } + c->mon = selmon; + c->next = systray->icons; + systray->icons = c; + if (!XGetWindowAttributes(dpy, c->win, &wa)) { + /* use sane defaults */ + wa.width = bh; + wa.height = bh; + wa.border_width = 0; + } + c->x = c->oldx = c->y = c->oldy = 0; + c->w = c->oldw = wa.width; + c->h = c->oldh = wa.height; + c->oldbw = wa.border_width; + c->bw = 0; + c->isfloating = True; + /* reuse tags field as mapped status */ + c->tags = 1; + updatesizehints(c); + updatesystrayicongeom(c, wa.width, wa.height); + XAddToSaveSet(dpy, c->win); + XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); + 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); + /* 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]) { + if (cme->data.l[1] == netatom[NetWMFullscreen] + || cme->data.l[2] == netatom[NetWMFullscreen]) + setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */ + || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen))); + } else if (cme->message_type == netatom[NetActiveWindow]) { + if (c != selmon->sel && !c->isurgent) + seturgent(c, 1); + } +} + +void +configure(Client *c) +{ + XConfigureEvent ce; + + ce.type = ConfigureNotify; + ce.display = dpy; + ce.event = c->win; + ce.window = c->win; + ce.x = c->x; + ce.y = c->y; + ce.width = c->w; + ce.height = c->h; + ce.border_width = c->bw; + ce.above = None; + ce.override_redirect = False; + XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce); +} + +void +configurenotify(XEvent *e) +{ + Monitor *m; + Client *c; + XConfigureEvent *ev = &e->xconfigure; + int dirty; + + /* TODO: updategeom handling sucks, needs to be simplified */ + if (ev->window == root) { + dirty = (sw != ev->width || sh != ev->height); + sw = ev->width; + sh = ev->height; + if (updategeom() || dirty) { + drw_resize(drw, sw, bh); + updatebars(); + for (m = mons; m; m = m->next) { + for (c = m->clients; c; c = c->next) + if (c->isfullscreen) + resizeclient(c, m->mx, m->my, m->mw, m->mh); + resizebarwin(m); + } + focus(NULL); + arrange(NULL); + } + } +} + +void +configurerequest(XEvent *e) +{ + Client *c; + Monitor *m; + XConfigureRequestEvent *ev = &e->xconfigurerequest; + XWindowChanges wc; + + if ((c = wintoclient(ev->window))) { + if (ev->value_mask & CWBorderWidth) + c->bw = ev->border_width; + else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) { + m = c->mon; + if (ev->value_mask & CWX) { + c->oldx = c->x; + c->x = m->mx + ev->x; + } + if (ev->value_mask & CWY) { + c->oldy = c->y; + c->y = m->my + ev->y; + } + if (ev->value_mask & CWWidth) { + c->oldw = c->w; + c->w = ev->width; + } + if (ev->value_mask & CWHeight) { + c->oldh = c->h; + c->h = ev->height; + } + if ((c->x + c->w) > m->mx + m->mw && c->isfloating) + c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */ + if ((c->y + c->h) > m->my + m->mh && c->isfloating) + c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */ + if ((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight))) + configure(c); + if (ISVISIBLE(c)) + XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); + } else + configure(c); + } else { + wc.x = ev->x; + wc.y = ev->y; + wc.width = ev->width; + wc.height = ev->height; + wc.border_width = ev->border_width; + wc.sibling = ev->above; + wc.stack_mode = ev->detail; + XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); + } + XSync(dpy, False); +} + +Monitor * +createmon(void) +{ + Monitor *m; + + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; + m->mfact = mfact; + m->nmaster = nmaster; + m->showbar = showbar; + m->topbar = topbar; + m->gappx = gappx; + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); + return m; +} + +void +destroynotify(XEvent *e) +{ + Client *c; + XDestroyWindowEvent *ev = &e->xdestroywindow; + + if ((c = wintoclient(ev->window))) + unmanage(c, 1); + else if ((c = wintosystrayicon(ev->window))) { + removesystrayicon(c); + resizebarwin(selmon); + updatesystray(); + } +} + +void +detach(Client *c) +{ + Client **tc; + + for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next); + *tc = c->next; +} + +void +detachstack(Client *c) +{ + Client **tc, *t; + + for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext); + *tc = c->snext; + + if (c == c->mon->sel) { + for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext); + c->mon->sel = t; + } +} + +Monitor * +dirtomon(int dir) +{ + Monitor *m = NULL; + + if (dir > 0) { + if (!(m = selmon->next)) + m = mons; + } else if (selmon == mons) + for (m = mons; m->next; m = m->next); + else + for (m = mons; m->next != selmon; m = m->next); + return m; +} + +void +drawbar(Monitor *m) +{ + int x, w, sw = 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]); + sw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ + drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0); + } + + resizebarwin(m); + 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 ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); + if (occ & 1 << i) + drw_rect(drw, x + boxs, boxs, boxw, boxw, + m == selmon && selmon->sel && selmon->sel->tags & 1 << i, + urg & 1 << i); + x += w; + } + w = 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 - 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); + 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_map(drw, m->barwin, 0, 0, m->ww - stw, bh); +} + +void +drawbars(void) +{ + Monitor *m; + + for (m = mons; m; m = m->next) + drawbar(m); +} + +void +enternotify(XEvent *e) +{ + Client *c; + Monitor *m; + XCrossingEvent *ev = &e->xcrossing; + + if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root) + return; + c = wintoclient(ev->window); + m = c ? c->mon : wintomon(ev->window); + if (m != selmon) { + unfocus(selmon->sel, 1); + selmon = m; + } else if (!c || c == selmon->sel) + return; + focus(c); +} + +void +expose(XEvent *e) +{ + Monitor *m; + XExposeEvent *ev = &e->xexpose; + + if (ev->count == 0 && (m = wintomon(ev->window))) { + drawbar(m); + if (m == selmon) + updatesystray(); + } +} + +void +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); + if (c) { + if (c->mon != selmon) + selmon = c->mon; + if (c->isurgent) + seturgent(c, 0); + detachstack(c); + attachstack(c); + grabbuttons(c, 1); + XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); + setfocus(c); + } else { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); + } + selmon->sel = c; + drawbars(); +} + +/* there are some broken focus acquiring clients needing extra handling */ +void +focusin(XEvent *e) +{ + XFocusChangeEvent *ev = &e->xfocus; + + if (selmon->sel && ev->window != selmon->sel->win) + setfocus(selmon->sel); +} + +void +focusmon(const Arg *arg) +{ + Monitor *m; + + if (!mons->next) + return; + if ((m = dirtomon(arg->i)) == selmon) + return; + unfocus(selmon->sel, 0); + selmon = m; + focus(NULL); +} + +void +focusstack(const Arg *arg) +{ + Client *c = NULL, *i; + + if (!selmon->sel) + return; + if (arg->i > 0) { + for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); + if (!c) + for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); + } else { + for (i = selmon->clients; i != selmon->sel; i = i->next) + if (ISVISIBLE(i)) + c = i; + if (!c) + for (; i; i = i->next) + if (ISVISIBLE(i)) + c = i; + } + if (c) { + focus(c); + restack(selmon); + } +} + +Atom +getatomprop(Client *c, Atom prop) +{ + int di; + 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, 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; +} + +int +getrootptr(int *x, int *y) +{ + int di; + unsigned int dui; + Window dummy; + + return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui); +} + +long +getstate(Window w) +{ + int format; + long result = -1; + unsigned char *p = NULL; + unsigned long n, extra; + Atom real; + + if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState], + &real, &format, &n, &extra, (unsigned char **)&p) != Success) + return -1; + if (n != 0) + result = *p; + XFree(p); + return result; +} + +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) +{ + char **list = NULL; + int n; + XTextProperty name; + + if (!text || size == 0) + return 0; + text[0] = '\0'; + if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems) + return 0; + if (name.encoding == XA_STRING) + strncpy(text, (char *)name.value, size - 1); + else { + if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) { + strncpy(text, *list, size - 1); + XFreeStringList(list); + } + } + text[size - 1] = '\0'; + XFree(name.value); + return 1; +} + +void +grabbuttons(Client *c, int focused) +{ + updatenumlockmask(); + { + unsigned int i, j; + unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); + if (!focused) + XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, + BUTTONMASK, GrabModeSync, GrabModeSync, None, None); + for (i = 0; i < LENGTH(buttons); i++) + if (buttons[i].click == ClkClientWin) + for (j = 0; j < LENGTH(modifiers); j++) + XGrabButton(dpy, buttons[i].button, + buttons[i].mask | modifiers[j], + c->win, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, None); + } +} + +void +grabkeys(void) +{ + updatenumlockmask(); + { + unsigned int i, j; + unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; + KeyCode code; + + XUngrabKey(dpy, AnyKey, AnyModifier, root); + for (i = 0; i < LENGTH(keys); i++) + if ((code = XKeysymToKeycode(dpy, keys[i].keysym))) + for (j = 0; j < LENGTH(modifiers); j++) + XGrabKey(dpy, code, keys[i].mod | modifiers[j], root, + True, GrabModeAsync, GrabModeAsync); + } +} + +void +incnmaster(const Arg *arg) +{ + selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); +} + +#ifdef XINERAMA +static int +isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) +{ + while (n--) + if (unique[n].x_org == info->x_org && unique[n].y_org == info->y_org + && unique[n].width == info->width && unique[n].height == info->height) + return 0; + return 1; +} +#endif /* XINERAMA */ + +void +keypress(XEvent *e) +{ + unsigned int i; + KeySym keysym; + XKeyEvent *ev; + + ev = &e->xkey; + keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); + for (i = 0; i < LENGTH(keys); i++) + if (keysym == keys[i].keysym + && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) + && keys[i].func) + keys[i].func(&(keys[i].arg)); +} + +void +killclient(const Arg *arg) +{ + if (!selmon->sel) + return; + if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { + XGrabServer(dpy); + XSetErrorHandler(xerrordummy); + XSetCloseDownMode(dpy, DestroyAll); + XKillClient(dpy, selmon->sel->win); + XSync(dpy, False); + XSetErrorHandler(xerror); + XUngrabServer(dpy); + } +} + +void +manage(Window w, XWindowAttributes *wa) +{ + Client *c, *t = NULL; + Window trans = None; + XWindowChanges wc; + + c = ecalloc(1, sizeof(Client)); + c->win = w; + /* geometry */ + c->x = c->oldx = wa->x; + c->y = c->oldy = wa->y; + c->w = c->oldw = wa->width; + c->h = c->oldh = wa->height; + c->oldbw = wa->border_width; + + updatetitle(c); + if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { + c->mon = t->mon; + c->tags = t->tags; + } else { + c->mon = selmon; + applyrules(c); + } + + if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw) + c->x = c->mon->mx + c->mon->mw - WIDTH(c); + if (c->y + HEIGHT(c) > c->mon->my + c->mon->mh) + 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->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); + configure(c); /* propagates border_width, if size doesn't change */ + updatewindowtype(c); + updatesizehints(c); + updatewmhints(c); + XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); + grabbuttons(c, 0); + if (!c->isfloating) + c->isfloating = c->oldstate = trans != None || c->isfixed; + if (c->isfloating) + XRaiseWindow(dpy, c->win); + attach(c); + attachstack(c); + XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); + XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ + setclientstate(c, NormalState); + if (c->mon == selmon) + unfocus(selmon->sel, 0); + c->mon->sel = c; + arrange(c->mon); + XMapWindow(dpy, c->win); + focus(NULL); +} + +void +mappingnotify(XEvent *e) +{ + XMappingEvent *ev = &e->xmapping; + + XRefreshKeyboardMapping(ev); + if (ev->request == MappingKeyboard) + grabkeys(); +} + +void +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; + if (wa.override_redirect) + return; + 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); +} + +void +motionnotify(XEvent *e) +{ + static Monitor *mon = NULL; + Monitor *m; + XMotionEvent *ev = &e->xmotion; + + if (ev->window != root) + return; + if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { + unfocus(selmon->sel, 1); + selmon = m; + focus(NULL); + } + mon = m; +} + +void +movemouse(const Arg *arg) +{ + int x, y, ocx, ocy, nx, ny; + Client *c; + Monitor *m; + XEvent ev; + Time lasttime = 0; + + if (!(c = selmon->sel)) + return; + if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ + return; + restack(selmon); + ocx = c->x; + ocy = c->y; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, + None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) + return; + if (!getrootptr(&x, &y)) + return; + do { + XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); + switch(ev.type) { + case ConfigureRequest: + case Expose: + case MapRequest: + handler[ev.type](&ev); + break; + case MotionNotify: + if ((ev.xmotion.time - lasttime) <= (1000 / 60)) + continue; + lasttime = ev.xmotion.time; + + nx = ocx + (ev.xmotion.x - x); + ny = ocy + (ev.xmotion.y - y); + if (abs(selmon->wx - nx) < snap) + nx = selmon->wx; + else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) + nx = selmon->wx + selmon->ww - WIDTH(c); + if (abs(selmon->wy - ny) < snap) + ny = selmon->wy; + else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap) + ny = selmon->wy + selmon->wh - HEIGHT(c); + if (!c->isfloating && selmon->lt[selmon->sellt]->arrange + && (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) + togglefloating(NULL); + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) + resize(c, nx, ny, c->w, c->h, 1); + break; + } + } while (ev.type != ButtonRelease); + XUngrabPointer(dpy, CurrentTime); + if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { + sendmon(c, m); + selmon = m; + focus(NULL); + } +} + +Client * +nexttiled(Client *c) +{ + for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); + return c; +} + +void +pop(Client *c) +{ + detach(c); + attach(c); + focus(c); + arrange(c->mon); +} + +void +propertynotify(XEvent *e) +{ + Client *c; + 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) + return; /* ignore */ + else if ((c = wintoclient(ev->window))) { + switch(ev->atom) { + default: break; + case XA_WM_TRANSIENT_FOR: + if (!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) && + (c->isfloating = (wintoclient(trans)) != NULL)) + arrange(c->mon); + break; + case XA_WM_NORMAL_HINTS: + updatesizehints(c); + break; + case XA_WM_HINTS: + updatewmhints(c); + drawbars(); + break; + } + if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { + updatetitle(c); + if (c == c->mon->sel) + drawbar(c->mon); + } + if (ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); + } +} + +void +quit(const Arg *arg) +{ + running = 0; +} + +Monitor * +recttomon(int x, int y, int w, int h) +{ + Monitor *m, *r = selmon; + int a, area = 0; + + for (m = mons; m; m = m->next) + if ((a = INTERSECT(x, y, w, h, m)) > area) { + area = a; + r = m; + } + return r; +} + +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) +{ + if (applysizehints(c, &x, &y, &w, &h, 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) +{ + XWindowChanges wc; + + c->oldx = c->x; c->x = wc.x = x; + c->oldy = c->y; c->y = wc.y = y; + c->oldw = c->w; c->w = wc.width = w; + c->oldh = c->h; c->h = wc.height = h; + wc.border_width = c->bw; + XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); + configure(c); + XSync(dpy, False); +} + +void +resizemouse(const Arg *arg) +{ + int ocx, ocy, nw, nh; + Client *c; + Monitor *m; + XEvent ev; + Time lasttime = 0; + + if (!(c = selmon->sel)) + return; + if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ + return; + restack(selmon); + ocx = c->x; + ocy = c->y; + 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); + 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; + + nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); + nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); + if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww + && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh) + { + if (!c->isfloating && selmon->lt[selmon->sellt]->arrange + && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) + togglefloating(NULL); + } + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) + resize(c, c->x, c->y, nw, nh, 1); + break; + } + } while (ev.type != ButtonRelease); + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); + XUngrabPointer(dpy, CurrentTime); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); + if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { + sendmon(c, m); + selmon = m; + focus(NULL); + } +} + +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) +{ + Client *c; + XEvent ev; + XWindowChanges wc; + + drawbar(m); + if (!m->sel) + return; + if (m->sel->isfloating || !m->lt[m->sellt]->arrange) + XRaiseWindow(dpy, m->sel->win); + if (m->lt[m->sellt]->arrange) { + wc.stack_mode = Below; + wc.sibling = m->barwin; + for (c = m->stack; c; c = c->snext) + if (!c->isfloating && ISVISIBLE(c)) { + XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc); + wc.sibling = c->win; + } + } + XSync(dpy, False); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); +} + +void +run(void) +{ + XEvent ev; + /* main event loop */ + XSync(dpy, False); + while (running && !XNextEvent(dpy, &ev)) + if (handler[ev.type]) + handler[ev.type](&ev); /* call handler */ +} + +void +runAutostart(void) { + system("cd ~/.config/dwm; ./autostart_blocking.sh"); + system("cd ~/.config/dwm; ./autostart.sh &"); +} + +void +scan(void) +{ + unsigned int i, num; + Window d1, d2, *wins = NULL; + XWindowAttributes wa; + + if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { + for (i = 0; i < num; i++) { + if (!XGetWindowAttributes(dpy, wins[i], &wa) + || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) + continue; + if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) + manage(wins[i], &wa); + } + for (i = 0; i < num; i++) { /* now the transients */ + if (!XGetWindowAttributes(dpy, wins[i], &wa)) + continue; + if (XGetTransientForHint(dpy, wins[i], &d1) + && (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)) + manage(wins[i], &wa); + } + if (wins) + XFree(wins); + } +} + +void +sendmon(Client *c, Monitor *m) +{ + if (c->mon == m) + return; + unfocus(c, 1); + detach(c); + detachstack(c); + c->mon = m; + c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ + attach(c); + attachstack(c); + focus(NULL); + arrange(NULL); +} + +void +setclientstate(Client *c, long state) +{ + long data[] = { state, None }; + + XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, + PropModeReplace, (unsigned char *)data, 2); +} + +int +sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) +{ + int n; + Atom *protocols, mt; + int exists = 0; + XEvent ev; + + 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 = 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); + } + return exists; +} + +void +setfocus(Client *c) +{ + if (!c->neverfocus) { + XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); + XChangeProperty(dpy, root, netatom[NetActiveWindow], + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(c->win), 1); + } + sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); +} + +void +setfullscreen(Client *c, int fullscreen) +{ + if (fullscreen && !c->isfullscreen) { + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, + PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); + c->isfullscreen = 1; + c->oldstate = c->isfloating; + c->oldbw = c->bw; + c->bw = 0; + c->isfloating = 1; + resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); + XRaiseWindow(dpy, c->win); + } else if (!fullscreen && c->isfullscreen){ + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, + PropModeReplace, (unsigned char*)0, 0); + c->isfullscreen = 0; + c->isfloating = c->oldstate; + c->bw = c->oldbw; + c->x = c->oldx; + c->y = c->oldy; + c->w = c->oldw; + c->h = c->oldh; + resizeclient(c, c->x, c->y, c->w, c->h); + arrange(c->mon); + } +} + +void +setgaps(const Arg *arg) +{ + if ((arg->i == 0) || (selmon->gappx + arg->i < 0)) + selmon->gappx = 0; + else + selmon->gappx += arg->i; + arrange(selmon); +} + +void +setlayout(const Arg *arg) +{ + if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) + selmon->sellt ^= 1; + if (arg && arg->v) + selmon->lt[selmon->sellt] = (Layout *)arg->v; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if (selmon->sel) + arrange(selmon); + else + drawbar(selmon); +} + +/* arg > 1.0 will set mfact absolutely */ +void +setmfact(const Arg *arg) +{ + float f; + + if (!arg || !selmon->lt[selmon->sellt]->arrange) + return; + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if (f < 0.1 || f > 0.9) + return; + selmon->mfact = f; + arrange(selmon); +} + +void +setup(void) +{ + int i; + XSetWindowAttributes wa; + Atom utf8string; + + /* clean up any zombies immediately */ + sigchld(0); + + /* init screen */ + screen = DefaultScreen(dpy); + sw = DisplayWidth(dpy, screen); + sh = DisplayHeight(dpy, screen); + root = RootWindow(dpy, screen); + 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; + updategeom(); + /* init atoms */ + utf8string = XInternAtom(dpy, "UTF8_STRING", False); + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); + wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); + wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); + netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); + netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); + netatom[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); + 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); + 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); + cursor[CurMove] = drw_cur_create(drw, XC_fleur); + /* init appearance */ + scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); + for (i = 0; i < LENGTH(colors); i++) + scheme[i] = drw_scm_create(drw, colors[i], 3); + /* init system tray */ + updatesystray(); + /* init bars */ + updatebars(); + updatestatus(); + /* supporting window for NetWMCheck */ + wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0); + XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32, + PropModeReplace, (unsigned char *) &wmcheckwin, 1); + XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8, + PropModeReplace, (unsigned char *) "dwm", 3); + XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32, + PropModeReplace, (unsigned char *) &wmcheckwin, 1); + /* EWMH support per view */ + XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, + PropModeReplace, (unsigned char *) netatom, NetLast); + XDeleteProperty(dpy, root, netatom[NetClientList]); + /* select events */ + wa.cursor = cursor[CurNormal]->cursor; + wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask + |ButtonPressMask|PointerMotionMask|EnterWindowMask + |LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; + XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); + XSelectInput(dpy, root, wa.event_mask); + grabkeys(); + focus(NULL); +} + + +void +seturgent(Client *c, int urg) +{ + XWMHints *wmh; + + c->isurgent = urg; + if (!(wmh = XGetWMHints(dpy, c->win))) + return; + wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint); + XSetWMHints(dpy, c->win, wmh); + XFree(wmh); +} + +void +showhide(Client *c) +{ + if (!c) + return; + if (ISVISIBLE(c)) { + /* show clients top down */ + XMoveWindow(dpy, c->win, c->x, c->y); + if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen) + resize(c, c->x, c->y, c->w, c->h, 0); + showhide(c->snext); + } else { + /* hide clients bottom up */ + showhide(c->snext); + XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y); + } +} + +void +sigchld(int unused) +{ + if (signal(SIGCHLD, sigchld) == SIG_ERR) + die("can't install SIGCHLD handler:"); + while (0 < waitpid(-1, NULL, WNOHANG)); +} + +void +spawn(const Arg *arg) +{ + if (arg->v == dmenucmd) + dmenumon[0] = '0' + selmon->num; + if (fork() == 0) { + if (dpy) + close(ConnectionNumber(dpy)); + setsid(); + execvp(((char **)arg->v)[0], (char **)arg->v); + fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]); + perror(" failed"); + exit(EXIT_SUCCESS); + } +} + +void +tag(const Arg *arg) +{ + if (selmon->sel && arg->ui & TAGMASK) { + selmon->sel->tags = arg->ui & TAGMASK; + focus(NULL); + arrange(selmon); + } +} + +void +tagmon(const Arg *arg) +{ + if (!selmon->sel || !mons->next) + return; + sendmon(selmon->sel, dirtomon(arg->i)); +} + +void +tile(Monitor *m) +{ + unsigned int i, n, h, mw, my, ty; + Client *c; + + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if (n == 0) + return; + + if (n > m->nmaster) + mw = m->nmaster ? m->ww * m->mfact : 0; + else + mw = m->ww - m->gappx; + for (i = 0, my = ty = m->gappx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { + h = (m->wh - my) / (MIN(n, m->nmaster) - i) - m->gappx; + resize(c, m->wx + m->gappx, m->wy + my, mw - (2*c->bw) - m->gappx, h - (2*c->bw), 0); + my += HEIGHT(c) + m->gappx; + } else { + h = (m->wh - ty) / (n - i) - m->gappx; + resize(c, m->wx + mw + m->gappx, m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->gappx, h - (2*c->bw), 0); + ty += HEIGHT(c) + m->gappx; + } +} + +void +togglebar(const Arg *arg) +{ + selmon->showbar = !selmon->showbar; + updatebarpos(selmon); + 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); +} + +void +togglefloating(const Arg *arg) +{ + if (!selmon->sel) + return; + if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ + return; + selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed; + if (selmon->sel->isfloating) + resize(selmon->sel, selmon->sel->x, selmon->sel->y, + selmon->sel->w, selmon->sel->h, 0); + arrange(selmon); +} + +void +toggletag(const Arg *arg) +{ + unsigned int newtags; + + if (!selmon->sel) + return; + newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); + if (newtags) { + selmon->sel->tags = newtags; + focus(NULL); + arrange(selmon); + } +} + +void +toggleview(const Arg *arg) +{ + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + + if (newtagset) { + selmon->tagset[selmon->seltags] = newtagset; + focus(NULL); + arrange(selmon); + } +} + +void +unfocus(Client *c, int setfocus) +{ + if (!c) + return; + grabbuttons(c, 0); + XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); + if (setfocus) { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); + } +} + +void +unmanage(Client *c, int destroyed) +{ + Monitor *m = c->mon; + XWindowChanges wc; + + detach(c); + detachstack(c); + if (!destroyed) { + wc.border_width = c->oldbw; + XGrabServer(dpy); /* avoid race conditions */ + XSetErrorHandler(xerrordummy); + XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */ + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); + setclientstate(c, WithdrawnState); + XSync(dpy, False); + XSetErrorHandler(xerror); + XUngrabServer(dpy); + } + free(c); + focus(NULL); + updateclientlist(); + arrange(m); +} + +void +unmapnotify(XEvent *e) +{ + Client *c; + XUnmapEvent *ev = &e->xunmap; + + if ((c = wintoclient(ev->window))) { + if (ev->send_event) + setclientstate(c, WithdrawnState); + 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, + .background_pixmap = ParentRelative, + .event_mask = ButtonPressMask|ExposureMask + }; + XClassHint ch = {"dwm", "dwm"}; + for (m = mons; m; m = m->next) { + if (m->barwin) + continue; + 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); + } +} + +void +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; + } else + m->by = -bh; +} + +void +updateclientlist() +{ + Client *c; + Monitor *m; + + XDeleteProperty(dpy, root, netatom[NetClientList]); + for (m = mons; m; m = m->next) + for (c = m->clients; c; c = c->next) + XChangeProperty(dpy, root, netatom[NetClientList], + XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); +} + +int +updategeom(void) +{ + int dirty = 0; + +#ifdef XINERAMA + if (XineramaIsActive(dpy)) { + int i, j, n, nn; + Client *c; + Monitor *m; + XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn); + XineramaScreenInfo *unique = NULL; + + for (n = 0, m = mons; m; m = m->next, n++); + /* only consider unique geometries as separate screens */ + unique = ecalloc(nn, sizeof(XineramaScreenInfo)); + for (i = 0, j = 0; i < nn; i++) + if (isuniquegeom(unique, j, &info[i])) + memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo)); + XFree(info); + nn = j; + if (n <= nn) { /* new monitors available */ + for (i = 0; i < (nn - n); i++) { + for (m = mons; m && m->next; m = m->next); + if (m) + m->next = createmon(); + else + mons = createmon(); + } + for (i = 0, m = mons; i < nn && m; m = m->next, i++) + if (i >= n + || unique[i].x_org != m->mx || unique[i].y_org != m->my + || unique[i].width != m->mw || unique[i].height != m->mh) + { + dirty = 1; + m->num = i; + m->mx = m->wx = unique[i].x_org; + m->my = m->wy = unique[i].y_org; + m->mw = m->ww = unique[i].width; + m->mh = m->wh = unique[i].height; + updatebarpos(m); + } + } else { /* less monitors available nn < n */ + for (i = nn; i < n; i++) { + for (m = mons; m && m->next; m = m->next); + while ((c = m->clients)) { + dirty = 1; + m->clients = c->next; + detachstack(c); + c->mon = mons; + attach(c); + attachstack(c); + } + if (m == selmon) + selmon = mons; + cleanupmon(m); + } + } + free(unique); + } else +#endif /* XINERAMA */ + { /* default monitor setup */ + if (!mons) + mons = createmon(); + if (mons->mw != sw || mons->mh != sh) { + dirty = 1; + mons->mw = mons->ww = sw; + mons->mh = mons->wh = sh; + updatebarpos(mons); + } + } + if (dirty) { + selmon = mons; + selmon = wintomon(root); + } + return dirty; +} + +void +updatenumlockmask(void) +{ + unsigned int i, j; + XModifierKeymap *modmap; + + numlockmask = 0; + modmap = XGetModifierMapping(dpy); + for (i = 0; i < 8; i++) + for (j = 0; j < modmap->max_keypermod; j++) + if (modmap->modifiermap[i * modmap->max_keypermod + j] + == XKeysymToKeycode(dpy, XK_Num_Lock)) + numlockmask = (1 << i); + XFreeModifiermap(modmap); +} + +void +updatesizehints(Client *c) +{ + long msize; + XSizeHints size; + + if (!XGetWMNormalHints(dpy, c->win, &size, &msize)) + /* size is uninitialized, ensure that size.flags aren't used */ + size.flags = PSize; + if (size.flags & PBaseSize) { + c->basew = size.base_width; + c->baseh = size.base_height; + } else if (size.flags & PMinSize) { + c->basew = size.min_width; + c->baseh = size.min_height; + } else + c->basew = c->baseh = 0; + if (size.flags & PResizeInc) { + c->incw = size.width_inc; + c->inch = size.height_inc; + } else + c->incw = c->inch = 0; + if (size.flags & PMaxSize) { + c->maxw = size.max_width; + c->maxh = size.max_height; + } else + c->maxw = c->maxh = 0; + if (size.flags & PMinSize) { + c->minw = size.min_width; + c->minh = size.min_height; + } else if (size.flags & PBaseSize) { + c->minw = size.base_width; + c->minh = size.base_height; + } else + c->minw = c->minh = 0; + if (size.flags & PAspect) { + c->mina = (float)size.min_aspect.y / size.min_aspect.x; + c->maxa = (float)size.max_aspect.x / size.max_aspect.y; + } else + c->maxa = c->mina = 0.0; + c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh); +} + +void +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 +updatetitle(Client *c) +{ + if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name)) + gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name); + if (c->name[0] == '\0') /* hack to mark broken clients */ + strcpy(c->name, broken); +} + +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; +} + +void +updatewmhints(Client *c) +{ + XWMHints *wmh; + + if ((wmh = XGetWMHints(dpy, c->win))) { + if (c == selmon->sel && wmh->flags & XUrgencyHint) { + wmh->flags &= ~XUrgencyHint; + XSetWMHints(dpy, c->win, wmh); + } else + c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0; + if (wmh->flags & InputHint) + c->neverfocus = !wmh->input; + else + c->neverfocus = 0; + XFree(wmh); + } +} + +void +view(const Arg *arg) +{ + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ + if (arg->ui & TAGMASK) + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + focus(NULL); + arrange(selmon); +} + +Client * +wintoclient(Window w) +{ + Client *c; + Monitor *m; + + for (m = mons; m; m = m->next) + for (c = m->clients; c; c = c->next) + if (c->win == w) + return c; + return NULL; +} + +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) +{ + int x, y; + Client *c; + Monitor *m; + + if (w == root && getrootptr(&x, &y)) + return recttomon(x, y, 1, 1); + for (m = mons; m; m = m->next) + if (w == m->barwin) + return m; + if ((c = wintoclient(w))) + return c->mon; + return selmon; +} + +/* 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. */ +int +xerror(Display *dpy, XErrorEvent *ee) +{ + if (ee->error_code == BadWindow + || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch) + || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable) + || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable) + || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable) + || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch) + || (ee->request_code == X_GrabButton && ee->error_code == BadAccess) + || (ee->request_code == X_GrabKey && ee->error_code == BadAccess) + || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable)) + return 0; + fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n", + ee->request_code, ee->error_code); + return xerrorxlib(dpy, ee); /* may call exit */ +} + +int +xerrordummy(Display *dpy, XErrorEvent *ee) +{ + return 0; +} + +/* Startup Error handler to check if another window manager + * is already running. */ +int +xerrorstart(Display *dpy, XErrorEvent *ee) +{ + die("dwm: another window manager is already running"); + return -1; +} + +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) +{ + Client *c = selmon->sel; + + if (!selmon->lt[selmon->sellt]->arrange + || (selmon->sel && selmon->sel->isfloating)) + return; + if (c == nexttiled(selmon->clients)) + if (!c || !(c = nexttiled(c->next))) + return; + pop(c); +} + +int +main(int argc, char *argv[]) +{ + if (argc == 2 && !strcmp("-v", argv[1])) + die("dwm-"VERSION); + else if (argc != 1) + die("usage: dwm [-v]"); + if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) + fputs("warning: no locale support\n", stderr); + if (!(dpy = XOpenDisplay(NULL))) + die("dwm: cannot open display"); + checkotherwm(); + setup(); +#ifdef __OpenBSD__ + if (pledge("stdio rpath proc exec", NULL) == -1) + die("pledge"); +#endif /* __OpenBSD__ */ + scan(); + runAutostart(); + run(); + cleanup(); + XCloseDisplay(dpy); + return EXIT_SUCCESS; +} diff --git a/stuff/manual-programs/suckless/dwm-bak/dwm.c.orig b/stuff/manual-programs/suckless/dwm-bak/dwm.c.orig new file mode 100644 index 0000000..0f0365a --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/dwm.c.orig @@ -0,0 +1,2516 @@ +/* See LICENSE file for copyright and license details. + * + * dynamic window manager is designed like any other X client as well. It is + * driven through handling X events. In contrast to other X clients, a window + * manager selects for SubstructureRedirectMask on the root window, to receive + * events about window (dis-)appearance. Only one X connection at a time is + * allowed to select for this event mask. + * + * The event handlers of dwm are organized in an array which is accessed + * whenever a new event has been fetched. This allows event dispatching + * in O(1) time. + * + * Each child of the root window is called a client, except windows which have + * set the override_redirect flag. Clients are organized in a linked client + * list on each monitor, the focus history is remembered through a stack list + * on each monitor. Each client contains a bit array to indicate the tags of a + * client. + * + * Keys and tagging rules are organized as arrays and defined in config.h. + * + * To understand everything else, start reading main(). + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef XINERAMA +#include +#endif /* XINERAMA */ +#include + +#include "drw.h" +#include "util.h" + +/* macros */ +#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) +#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) +#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ + * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) +#define 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 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 */ + +typedef union { + int i; + unsigned int ui; + float f; + const void *v; +} Arg; + +typedef struct { + unsigned int click; + unsigned int mask; + unsigned int button; + void (*func)(const Arg *arg); + const Arg arg; +} Button; + +typedef struct Monitor Monitor; +typedef struct Client Client; +struct Client { + char name[256]; + float mina, maxa; + int x, y, w, h; + int oldx, oldy, oldw, oldh; + int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int bw, oldbw; + unsigned int tags; + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; + Client *next; + Client *snext; + Monitor *mon; + Window win; +}; + +typedef struct { + unsigned int mod; + KeySym keysym; + void (*func)(const Arg *); + const Arg arg; +} Key; + +typedef struct { + const char *symbol; + void (*arrange)(Monitor *); +} Layout; + +struct Monitor { + char ltsymbol[16]; + float mfact; + int nmaster; + int num; + int by; /* bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ + int gappx; /* gaps between windows */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; + int showbar; + int topbar; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; + const Layout *lt[2]; +}; + +typedef struct { + const char *class; + const char *instance; + const char *title; + unsigned int tags; + int isfloating; + int monitor; +} Rule; + +typedef struct Systray Systray; +struct Systray { + Window win; + Client *icons; +}; + +/* function declarations */ +static void applyrules(Client *c); +static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); +static void arrange(Monitor *m); +static void arrangemon(Monitor *m); +static void attach(Client *c); +static void attachstack(Client *c); +static void buttonpress(XEvent *e); +static void checkotherwm(void); +static void cleanup(void); +static void cleanupmon(Monitor *mon); +static void clientmessage(XEvent *e); +static void configure(Client *c); +static void configurenotify(XEvent *e); +static void configurerequest(XEvent *e); +static Monitor *createmon(void); +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 enternotify(XEvent *e); +static void expose(XEvent *e); +static void focus(Client *c); +static void focusin(XEvent *e); +static void focusmon(const Arg *arg); +static void 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); +static void incnmaster(const Arg *arg); +static void keypress(XEvent *e); +static void killclient(const Arg *arg); +static void manage(Window w, XWindowAttributes *wa); +static void mappingnotify(XEvent *e); +static void maprequest(XEvent *e); +static void monocle(Monitor *m); +static void motionnotify(XEvent *e); +static void movemouse(const Arg *arg); +static Client *nexttiled(Client *c); +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(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); +static void setfullscreen(Client *c, int fullscreen); +static void setgaps(const Arg *arg); +static void setlayout(const Arg *arg); +static void setmfact(const Arg *arg); +static void setup(void); +static void seturgent(Client *c, int urg); +static void 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 *); +static void togglebar(const Arg *arg); +static void togglefloating(const Arg *arg); +static void toggletag(const Arg *arg); +static void toggleview(const Arg *arg); +static void unfocus(Client *c, int setfocus); +static void unmanage(Client *c, int destroyed); +static void unmapnotify(XEvent *e); +static void updatebarpos(Monitor *m); +static void updatebars(void); +static void updateclientlist(void); +static 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; +static int sw, sh; /* X display screen geometry width, height */ +static int bh, blw = 0; /* bar geometry */ +static int lrpad; /* sum of left and right padding for text */ +static int (*xerrorxlib)(Display *, XErrorEvent *); +static unsigned int numlockmask = 0; +static void (*handler[LASTEvent]) (XEvent *) = { + [ButtonPress] = buttonpress, + [ClientMessage] = clientmessage, + [ConfigureRequest] = configurerequest, + [ConfigureNotify] = configurenotify, + [DestroyNotify] = destroynotify, + //[EnterNotify] = enternotify, + [Expose] = expose, + [FocusIn] = focusin, + [KeyPress] = keypress, + [MappingNotify] = mappingnotify, + [MapRequest] = maprequest, + [MotionNotify] = motionnotify, + [PropertyNotify] = propertynotify, + [ResizeRequest] = resizerequest, + [UnmapNotify] = unmapnotify +}; +static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; +static int running = 1; +static Cur *cursor[CurLast]; +static Clr **scheme; +static Display *dpy; +static Drw *drw; +static Monitor *mons, *selmon; +static Window root, wmcheckwin; + +/* configuration, allows nested code to access above variables */ +#include "config.h" + +/* compile-time check if all tags fit into an unsigned int bit array. */ +struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +/* function implementations */ +void +applyrules(Client *c) +{ + const char *class, *instance; + unsigned int i; + const Rule *r; + Monitor *m; + XClassHint ch = { NULL, NULL }; + + /* rule matching */ + c->isfloating = 0; + c->tags = 0; + XGetClassHint(dpy, c->win, &ch); + class = ch.res_class ? ch.res_class : broken; + instance = ch.res_name ? ch.res_name : broken; + + for (i = 0; i < LENGTH(rules); i++) { + r = &rules[i]; + if ((!r->title || strstr(c->name, r->title)) + && (!r->class || strstr(class, r->class)) + && (!r->instance || strstr(instance, r->instance))) + { + c->isfloating = r->isfloating; + c->tags |= r->tags; + for (m = mons; m && m->num != r->monitor; m = m->next); + if (m) + c->mon = m; + } + } + if (ch.res_class) + XFree(ch.res_class); + if (ch.res_name) + XFree(ch.res_name); + c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; +} + +int +applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) +{ + int baseismin; + Monitor *m = c->mon; + + /* set minimum possible */ + *w = MAX(1, *w); + *h = MAX(1, *h); + if (interact) { + if (*x > sw) + *x = sw - WIDTH(c); + if (*y > sh) + *y = sh - HEIGHT(c); + if (*x + *w + 2 * c->bw < 0) + *x = 0; + if (*y + *h + 2 * c->bw < 0) + *y = 0; + } else { + if (*x >= m->wx + m->ww) + *x = m->wx + m->ww - WIDTH(c); + if (*y >= m->wy + m->wh) + *y = m->wy + m->wh - HEIGHT(c); + if (*x + *w + 2 * c->bw <= m->wx) + *x = m->wx; + if (*y + *h + 2 * c->bw <= m->wy) + *y = m->wy; + } + if (*h < bh) + *h = bh; + if (*w < bh) + *w = bh; + if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { + /* see last two sentences in ICCCM 4.1.2.3 */ + baseismin = c->basew == c->minw && c->baseh == c->minh; + if (!baseismin) { /* temporarily remove base dimensions */ + *w -= c->basew; + *h -= c->baseh; + } + /* adjust for aspect limits */ + if (c->mina > 0 && c->maxa > 0) { + if (c->maxa < (float)*w / *h) + *w = *h * c->maxa + 0.5; + else if (c->mina < (float)*h / *w) + *h = *w * c->mina + 0.5; + } + if (baseismin) { /* increment calculation requires this */ + *w -= c->basew; + *h -= c->baseh; + } + /* adjust for increment value */ + if (c->incw) + *w -= *w % c->incw; + if (c->inch) + *h -= *h % c->inch; + /* restore base dimensions */ + *w = MAX(*w + c->basew, c->minw); + *h = MAX(*h + c->baseh, c->minh); + if (c->maxw) + *w = MIN(*w, c->maxw); + if (c->maxh) + *h = MIN(*h, c->maxh); + } + return *x != c->x || *y != c->y || *w != c->w || *h != c->h; +} + +void +arrange(Monitor *m) +{ + if (m) + showhide(m->stack); + else for (m = mons; m; m = m->next) + showhide(m->stack); + if (m) { + arrangemon(m); + restack(m); + } else for (m = mons; m; m = m->next) + arrangemon(m); +} + +void +arrangemon(Monitor *m) +{ + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); + if (m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); +} + +void +attach(Client *c) +{ + c->next = c->mon->clients; + c->mon->clients = c; +} + +void +attachstack(Client *c) +{ + c->snext = c->mon->stack; + c->mon->stack = c; +} + +void +buttonpress(XEvent *e) +{ + unsigned int i, x, click; + Arg arg = {0}; + Client *c; + Monitor *m; + XButtonPressedEvent *ev = &e->xbutton; + + click = ClkRootWin; + /* focus monitor if necessary */ + if ((m = wintomon(ev->window)) && m != selmon) { + unfocus(selmon->sel, 1); + selmon = m; + focus(NULL); + } + if (ev->window == selmon->barwin) { + i = x = 0; + 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 - TEXTW(stext) - getsystraywidth()) + click = ClkStatusText; + else + click = ClkWinTitle; + } else if ((c = wintoclient(ev->window))) { + focus(c); + restack(selmon); + XAllowEvents(dpy, ReplayPointer, CurrentTime); + click = ClkClientWin; + } + for (i = 0; i < LENGTH(buttons); i++) + if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button + && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) + buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); +} + +void +checkotherwm(void) +{ + xerrorxlib = XSetErrorHandler(xerrorstart); + /* this causes an error if some other window manager is running */ + XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask); + XSync(dpy, False); + XSetErrorHandler(xerror); + XSync(dpy, False); +} + +void +cleanup(void) +{ + Arg a = {.ui = ~0}; + Layout foo = { "", NULL }; + Monitor *m; + size_t i; + + view(&a); + selmon->lt[selmon->sellt] = &foo; + for (m = mons; m; m = m->next) + while (m->stack) + unmanage(m->stack, 0); + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); + if (showsystray) { + XUnmapWindow(dpy, systray->win); + XDestroyWindow(dpy, systray->win); + free(systray); + } + for (i = 0; i < CurLast; i++) + drw_cur_free(drw, cursor[i]); + for (i = 0; i < LENGTH(colors); i++) + free(scheme[i]); + XDestroyWindow(dpy, wmcheckwin); + drw_free(drw); + XSync(dpy, False); + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); +} + +void +cleanupmon(Monitor *mon) +{ + Monitor *m; + + if (mon == mons) + mons = mons->next; + else { + for (m = mons; m && m->next != mon; m = m->next); + m->next = mon->next; + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); + free(mon); +} + +void +clientmessage(XEvent *e) +{ + XWindowAttributes wa; + XSetWindowAttributes swa; + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); + + if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { + /* add systray icons */ + if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { + if (!(c = (Client *)calloc(1, sizeof(Client)))) + die("fatal: could not malloc() %u bytes\n", sizeof(Client)); + if (!(c->win = cme->data.l[2])) { + free(c); + return; + } + c->mon = selmon; + c->next = systray->icons; + systray->icons = c; + if (!XGetWindowAttributes(dpy, c->win, &wa)) { + /* use sane defaults */ + wa.width = bh; + wa.height = bh; + wa.border_width = 0; + } + c->x = c->oldx = c->y = c->oldy = 0; + c->w = c->oldw = wa.width; + c->h = c->oldh = wa.height; + c->oldbw = wa.border_width; + c->bw = 0; + c->isfloating = True; + /* reuse tags field as mapped status */ + c->tags = 1; + updatesizehints(c); + updatesystrayicongeom(c, wa.width, wa.height); + XAddToSaveSet(dpy, c->win); + XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); + 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); + /* 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]) { + if (cme->data.l[1] == netatom[NetWMFullscreen] + || cme->data.l[2] == netatom[NetWMFullscreen]) + setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */ + || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen))); + } else if (cme->message_type == netatom[NetActiveWindow]) { + if (c != selmon->sel && !c->isurgent) + seturgent(c, 1); + } +} + +void +configure(Client *c) +{ + XConfigureEvent ce; + + ce.type = ConfigureNotify; + ce.display = dpy; + ce.event = c->win; + ce.window = c->win; + ce.x = c->x; + ce.y = c->y; + ce.width = c->w; + ce.height = c->h; + ce.border_width = c->bw; + ce.above = None; + ce.override_redirect = False; + XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce); +} + +void +configurenotify(XEvent *e) +{ + Monitor *m; + Client *c; + XConfigureEvent *ev = &e->xconfigure; + int dirty; + + /* TODO: updategeom handling sucks, needs to be simplified */ + if (ev->window == root) { + dirty = (sw != ev->width || sh != ev->height); + sw = ev->width; + sh = ev->height; + if (updategeom() || dirty) { + drw_resize(drw, sw, bh); + updatebars(); + for (m = mons; m; m = m->next) { + for (c = m->clients; c; c = c->next) + if (c->isfullscreen) + resizeclient(c, m->mx, m->my, m->mw, m->mh); + resizebarwin(m); + } + focus(NULL); + arrange(NULL); + } + } +} + +void +configurerequest(XEvent *e) +{ + Client *c; + Monitor *m; + XConfigureRequestEvent *ev = &e->xconfigurerequest; + XWindowChanges wc; + + if ((c = wintoclient(ev->window))) { + if (ev->value_mask & CWBorderWidth) + c->bw = ev->border_width; + else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) { + m = c->mon; + if (ev->value_mask & CWX) { + c->oldx = c->x; + c->x = m->mx + ev->x; + } + if (ev->value_mask & CWY) { + c->oldy = c->y; + c->y = m->my + ev->y; + } + if (ev->value_mask & CWWidth) { + c->oldw = c->w; + c->w = ev->width; + } + if (ev->value_mask & CWHeight) { + c->oldh = c->h; + c->h = ev->height; + } + if ((c->x + c->w) > m->mx + m->mw && c->isfloating) + c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */ + if ((c->y + c->h) > m->my + m->mh && c->isfloating) + c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */ + if ((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight))) + configure(c); + if (ISVISIBLE(c)) + XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); + } else + configure(c); + } else { + wc.x = ev->x; + wc.y = ev->y; + wc.width = ev->width; + wc.height = ev->height; + wc.border_width = ev->border_width; + wc.sibling = ev->above; + wc.stack_mode = ev->detail; + XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); + } + XSync(dpy, False); +} + +Monitor * +createmon(void) +{ + Monitor *m; + + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; + m->mfact = mfact; + m->nmaster = nmaster; + m->showbar = showbar; + m->topbar = topbar; + m->gappx = gappx; + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); + return m; +} + +void +destroynotify(XEvent *e) +{ + Client *c; + XDestroyWindowEvent *ev = &e->xdestroywindow; + + if ((c = wintoclient(ev->window))) + unmanage(c, 1); + else if ((c = wintosystrayicon(ev->window))) { + removesystrayicon(c); + resizebarwin(selmon); + updatesystray(); + } +} + +void +detach(Client *c) +{ + Client **tc; + + for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next); + *tc = c->next; +} + +void +detachstack(Client *c) +{ + Client **tc, *t; + + for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext); + *tc = c->snext; + + if (c == c->mon->sel) { + for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext); + c->mon->sel = t; + } +} + +Monitor * +dirtomon(int dir) +{ + Monitor *m = NULL; + + if (dir > 0) { + if (!(m = selmon->next)) + m = mons; + } else if (selmon == mons) + for (m = mons; m->next; m = m->next); + else + for (m = mons; m->next != selmon; m = m->next); + return m; +} + +void +drawbar(Monitor *m) +{ + int x, w, sw = 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]); + sw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ + drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0); + } + + resizebarwin(m); + 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 ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); + if (occ & 1 << i) + drw_rect(drw, x + boxs, boxs, boxw, boxw, + m == selmon && selmon->sel && selmon->sel->tags & 1 << i, + urg & 1 << i); + x += w; + } + w = 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 - 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); + 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_map(drw, m->barwin, 0, 0, m->ww - stw, bh); +} + +void +drawbars(void) +{ + Monitor *m; + + for (m = mons; m; m = m->next) + drawbar(m); +} + +void +enternotify(XEvent *e) +{ + Client *c; + Monitor *m; + XCrossingEvent *ev = &e->xcrossing; + + if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root) + return; + c = wintoclient(ev->window); + m = c ? c->mon : wintomon(ev->window); + if (m != selmon) { + unfocus(selmon->sel, 1); + selmon = m; + } else if (!c || c == selmon->sel) + return; + focus(c); +} + +void +expose(XEvent *e) +{ + Monitor *m; + XExposeEvent *ev = &e->xexpose; + + if (ev->count == 0 && (m = wintomon(ev->window))) { + drawbar(m); + if (m == selmon) + updatesystray(); + } +} + +void +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); + if (c) { + if (c->mon != selmon) + selmon = c->mon; + if (c->isurgent) + seturgent(c, 0); + detachstack(c); + attachstack(c); + grabbuttons(c, 1); + XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); + setfocus(c); + } else { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); + } + selmon->sel = c; + drawbars(); +} + +/* there are some broken focus acquiring clients needing extra handling */ +void +focusin(XEvent *e) +{ + XFocusChangeEvent *ev = &e->xfocus; + + if (selmon->sel && ev->window != selmon->sel->win) + setfocus(selmon->sel); +} + +void +focusmon(const Arg *arg) +{ + Monitor *m; + + if (!mons->next) + return; + if ((m = dirtomon(arg->i)) == selmon) + return; + unfocus(selmon->sel, 0); + selmon = m; + focus(NULL); +} + +void +focusstack(const Arg *arg) +{ + Client *c = NULL, *i; + + if (!selmon->sel) + return; + if (arg->i > 0) { + for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); + if (!c) + for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); + } else { + for (i = selmon->clients; i != selmon->sel; i = i->next) + if (ISVISIBLE(i)) + c = i; + if (!c) + for (; i; i = i->next) + if (ISVISIBLE(i)) + c = i; + } + if (c) { + focus(c); + restack(selmon); + } +} + +Atom +getatomprop(Client *c, Atom prop) +{ + int di; + 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, 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; +} + +int +getrootptr(int *x, int *y) +{ + int di; + unsigned int dui; + Window dummy; + + return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui); +} + +long +getstate(Window w) +{ + int format; + long result = -1; + unsigned char *p = NULL; + unsigned long n, extra; + Atom real; + + if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState], + &real, &format, &n, &extra, (unsigned char **)&p) != Success) + return -1; + if (n != 0) + result = *p; + XFree(p); + return result; +} + +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) +{ + char **list = NULL; + int n; + XTextProperty name; + + if (!text || size == 0) + return 0; + text[0] = '\0'; + if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems) + return 0; + if (name.encoding == XA_STRING) + strncpy(text, (char *)name.value, size - 1); + else { + if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) { + strncpy(text, *list, size - 1); + XFreeStringList(list); + } + } + text[size - 1] = '\0'; + XFree(name.value); + return 1; +} + +void +grabbuttons(Client *c, int focused) +{ + updatenumlockmask(); + { + unsigned int i, j; + unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); + if (!focused) + XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, + BUTTONMASK, GrabModeSync, GrabModeSync, None, None); + for (i = 0; i < LENGTH(buttons); i++) + if (buttons[i].click == ClkClientWin) + for (j = 0; j < LENGTH(modifiers); j++) + XGrabButton(dpy, buttons[i].button, + buttons[i].mask | modifiers[j], + c->win, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, None); + } +} + +void +grabkeys(void) +{ + updatenumlockmask(); + { + unsigned int i, j; + unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; + KeyCode code; + + XUngrabKey(dpy, AnyKey, AnyModifier, root); + for (i = 0; i < LENGTH(keys); i++) + if ((code = XKeysymToKeycode(dpy, keys[i].keysym))) + for (j = 0; j < LENGTH(modifiers); j++) + XGrabKey(dpy, code, keys[i].mod | modifiers[j], root, + True, GrabModeAsync, GrabModeAsync); + } +} + +void +incnmaster(const Arg *arg) +{ + selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); +} + +#ifdef XINERAMA +static int +isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) +{ + while (n--) + if (unique[n].x_org == info->x_org && unique[n].y_org == info->y_org + && unique[n].width == info->width && unique[n].height == info->height) + return 0; + return 1; +} +#endif /* XINERAMA */ + +void +keypress(XEvent *e) +{ + unsigned int i; + KeySym keysym; + XKeyEvent *ev; + + ev = &e->xkey; + keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); + for (i = 0; i < LENGTH(keys); i++) + if (keysym == keys[i].keysym + && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) + && keys[i].func) + keys[i].func(&(keys[i].arg)); +} + +void +killclient(const Arg *arg) +{ + if (!selmon->sel) + return; + if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { + XGrabServer(dpy); + XSetErrorHandler(xerrordummy); + XSetCloseDownMode(dpy, DestroyAll); + XKillClient(dpy, selmon->sel->win); + XSync(dpy, False); + XSetErrorHandler(xerror); + XUngrabServer(dpy); + } +} + +void +manage(Window w, XWindowAttributes *wa) +{ + Client *c, *t = NULL; + Window trans = None; + XWindowChanges wc; + + c = ecalloc(1, sizeof(Client)); + c->win = w; + /* geometry */ + c->x = c->oldx = wa->x; + c->y = c->oldy = wa->y; + c->w = c->oldw = wa->width; + c->h = c->oldh = wa->height; + c->oldbw = wa->border_width; + + updatetitle(c); + if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { + c->mon = t->mon; + c->tags = t->tags; + } else { + c->mon = selmon; + applyrules(c); + } + + if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw) + c->x = c->mon->mx + c->mon->mw - WIDTH(c); + if (c->y + HEIGHT(c) > c->mon->my + c->mon->mh) + 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->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); + configure(c); /* propagates border_width, if size doesn't change */ + updatewindowtype(c); + updatesizehints(c); + updatewmhints(c); + XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); + grabbuttons(c, 0); + if (!c->isfloating) + c->isfloating = c->oldstate = trans != None || c->isfixed; + if (c->isfloating) + XRaiseWindow(dpy, c->win); + attach(c); + attachstack(c); + XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); + XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ + setclientstate(c, NormalState); + if (c->mon == selmon) + unfocus(selmon->sel, 0); + c->mon->sel = c; + arrange(c->mon); + XMapWindow(dpy, c->win); + focus(NULL); +} + +void +mappingnotify(XEvent *e) +{ + XMappingEvent *ev = &e->xmapping; + + XRefreshKeyboardMapping(ev); + if (ev->request == MappingKeyboard) + grabkeys(); +} + +void +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; + if (wa.override_redirect) + return; + 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); +} + +void +motionnotify(XEvent *e) +{ + static Monitor *mon = NULL; + Monitor *m; + XMotionEvent *ev = &e->xmotion; + + if (ev->window != root) + return; + if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { + unfocus(selmon->sel, 1); + selmon = m; + focus(NULL); + } + mon = m; +} + +void +movemouse(const Arg *arg) +{ + int x, y, ocx, ocy, nx, ny; + Client *c; + Monitor *m; + XEvent ev; + Time lasttime = 0; + + if (!(c = selmon->sel)) + return; + if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ + return; + restack(selmon); + ocx = c->x; + ocy = c->y; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, + None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) + return; + if (!getrootptr(&x, &y)) + return; + do { + XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); + switch(ev.type) { + case ConfigureRequest: + case Expose: + case MapRequest: + handler[ev.type](&ev); + break; + case MotionNotify: + if ((ev.xmotion.time - lasttime) <= (1000 / 60)) + continue; + lasttime = ev.xmotion.time; + + nx = ocx + (ev.xmotion.x - x); + ny = ocy + (ev.xmotion.y - y); + if (abs(selmon->wx - nx) < snap) + nx = selmon->wx; + else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) + nx = selmon->wx + selmon->ww - WIDTH(c); + if (abs(selmon->wy - ny) < snap) + ny = selmon->wy; + else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap) + ny = selmon->wy + selmon->wh - HEIGHT(c); + if (!c->isfloating && selmon->lt[selmon->sellt]->arrange + && (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) + togglefloating(NULL); + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) + resize(c, nx, ny, c->w, c->h, 1); + break; + } + } while (ev.type != ButtonRelease); + XUngrabPointer(dpy, CurrentTime); + if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { + sendmon(c, m); + selmon = m; + focus(NULL); + } +} + +Client * +nexttiled(Client *c) +{ + for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); + return c; +} + +void +pop(Client *c) +{ + detach(c); + attach(c); + focus(c); + arrange(c->mon); +} + +void +propertynotify(XEvent *e) +{ + Client *c; + 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) + return; /* ignore */ + else if ((c = wintoclient(ev->window))) { + switch(ev->atom) { + default: break; + case XA_WM_TRANSIENT_FOR: + if (!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) && + (c->isfloating = (wintoclient(trans)) != NULL)) + arrange(c->mon); + break; + case XA_WM_NORMAL_HINTS: + updatesizehints(c); + break; + case XA_WM_HINTS: + updatewmhints(c); + drawbars(); + break; + } + if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { + updatetitle(c); + if (c == c->mon->sel) + drawbar(c->mon); + } + if (ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); + } +} + +void +quit(const Arg *arg) +{ + running = 0; +} + +Monitor * +recttomon(int x, int y, int w, int h) +{ + Monitor *m, *r = selmon; + int a, area = 0; + + for (m = mons; m; m = m->next) + if ((a = INTERSECT(x, y, w, h, m)) > area) { + area = a; + r = m; + } + return r; +} + +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) +{ + if (applysizehints(c, &x, &y, &w, &h, 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) +{ + XWindowChanges wc; + + c->oldx = c->x; c->x = wc.x = x; + c->oldy = c->y; c->y = wc.y = y; + c->oldw = c->w; c->w = wc.width = w; + c->oldh = c->h; c->h = wc.height = h; + wc.border_width = c->bw; + XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); + configure(c); + XSync(dpy, False); +} + +void +resizemouse(const Arg *arg) +{ + int ocx, ocy, nw, nh; + Client *c; + Monitor *m; + XEvent ev; + Time lasttime = 0; + + if (!(c = selmon->sel)) + return; + if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ + return; + restack(selmon); + ocx = c->x; + ocy = c->y; + 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); + 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; + + nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); + nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); + if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww + && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh) + { + if (!c->isfloating && selmon->lt[selmon->sellt]->arrange + && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) + togglefloating(NULL); + } + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) + resize(c, c->x, c->y, nw, nh, 1); + break; + } + } while (ev.type != ButtonRelease); + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); + XUngrabPointer(dpy, CurrentTime); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); + if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { + sendmon(c, m); + selmon = m; + focus(NULL); + } +} + +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) +{ + Client *c; + XEvent ev; + XWindowChanges wc; + + drawbar(m); + if (!m->sel) + return; + if (m->sel->isfloating || !m->lt[m->sellt]->arrange) + XRaiseWindow(dpy, m->sel->win); + if (m->lt[m->sellt]->arrange) { + wc.stack_mode = Below; + wc.sibling = m->barwin; + for (c = m->stack; c; c = c->snext) + if (!c->isfloating && ISVISIBLE(c)) { + XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc); + wc.sibling = c->win; + } + } + XSync(dpy, False); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); +} + +void +run(void) +{ + XEvent ev; + /* main event loop */ + XSync(dpy, False); + while (running && !XNextEvent(dpy, &ev)) + if (handler[ev.type]) + handler[ev.type](&ev); /* call handler */ +} + +void +scan(void) +{ + unsigned int i, num; + Window d1, d2, *wins = NULL; + XWindowAttributes wa; + + if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { + for (i = 0; i < num; i++) { + if (!XGetWindowAttributes(dpy, wins[i], &wa) + || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) + continue; + if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) + manage(wins[i], &wa); + } + for (i = 0; i < num; i++) { /* now the transients */ + if (!XGetWindowAttributes(dpy, wins[i], &wa)) + continue; + if (XGetTransientForHint(dpy, wins[i], &d1) + && (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)) + manage(wins[i], &wa); + } + if (wins) + XFree(wins); + } +} + +void +sendmon(Client *c, Monitor *m) +{ + if (c->mon == m) + return; + unfocus(c, 1); + detach(c); + detachstack(c); + c->mon = m; + c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ + attach(c); + attachstack(c); + focus(NULL); + arrange(NULL); +} + +void +setclientstate(Client *c, long state) +{ + long data[] = { state, None }; + + XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, + PropModeReplace, (unsigned char *)data, 2); +} + +int +sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) +{ + int n; + Atom *protocols, mt; + int exists = 0; + XEvent ev; + + 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 = 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); + } + return exists; +} + +void +setfocus(Client *c) +{ + if (!c->neverfocus) { + XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); + XChangeProperty(dpy, root, netatom[NetActiveWindow], + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(c->win), 1); + } + sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); +} + +void +setfullscreen(Client *c, int fullscreen) +{ + if (fullscreen && !c->isfullscreen) { + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, + PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); + c->isfullscreen = 1; + c->oldstate = c->isfloating; + c->oldbw = c->bw; + c->bw = 0; + c->isfloating = 1; + resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); + XRaiseWindow(dpy, c->win); + } else if (!fullscreen && c->isfullscreen){ + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, + PropModeReplace, (unsigned char*)0, 0); + c->isfullscreen = 0; + c->isfloating = c->oldstate; + c->bw = c->oldbw; + c->x = c->oldx; + c->y = c->oldy; + c->w = c->oldw; + c->h = c->oldh; + resizeclient(c, c->x, c->y, c->w, c->h); + arrange(c->mon); + } +} + +void +setgaps(const Arg *arg) +{ + if ((arg->i == 0) || (selmon->gappx + arg->i < 0)) + selmon->gappx = 0; + else + selmon->gappx += arg->i; + arrange(selmon); +} + +void +setlayout(const Arg *arg) +{ + if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) + selmon->sellt ^= 1; + if (arg && arg->v) + selmon->lt[selmon->sellt] = (Layout *)arg->v; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if (selmon->sel) + arrange(selmon); + else + drawbar(selmon); +} + +/* arg > 1.0 will set mfact absolutely */ +void +setmfact(const Arg *arg) +{ + float f; + + if (!arg || !selmon->lt[selmon->sellt]->arrange) + return; + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if (f < 0.1 || f > 0.9) + return; + selmon->mfact = f; + arrange(selmon); +} + +void +setup(void) +{ + int i; + XSetWindowAttributes wa; + Atom utf8string; + + /* clean up any zombies immediately */ + sigchld(0); + + /* init screen */ + screen = DefaultScreen(dpy); + sw = DisplayWidth(dpy, screen); + sh = DisplayHeight(dpy, screen); + root = RootWindow(dpy, screen); + 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; + updategeom(); + /* init atoms */ + utf8string = XInternAtom(dpy, "UTF8_STRING", False); + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); + wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); + wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); + netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); + netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); + netatom[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); + 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); + 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); + cursor[CurMove] = drw_cur_create(drw, XC_fleur); + /* init appearance */ + scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); + for (i = 0; i < LENGTH(colors); i++) + scheme[i] = drw_scm_create(drw, colors[i], 3); + /* init system tray */ + updatesystray(); + /* init bars */ + updatebars(); + updatestatus(); + /* supporting window for NetWMCheck */ + wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0); + XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32, + PropModeReplace, (unsigned char *) &wmcheckwin, 1); + XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8, + PropModeReplace, (unsigned char *) "dwm", 3); + XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32, + PropModeReplace, (unsigned char *) &wmcheckwin, 1); + /* EWMH support per view */ + XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, + PropModeReplace, (unsigned char *) netatom, NetLast); + XDeleteProperty(dpy, root, netatom[NetClientList]); + /* select events */ + wa.cursor = cursor[CurNormal]->cursor; + wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask + |ButtonPressMask|PointerMotionMask|EnterWindowMask + |LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; + XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); + XSelectInput(dpy, root, wa.event_mask); + grabkeys(); + focus(NULL); +} + + +void +seturgent(Client *c, int urg) +{ + XWMHints *wmh; + + c->isurgent = urg; + if (!(wmh = XGetWMHints(dpy, c->win))) + return; + wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint); + XSetWMHints(dpy, c->win, wmh); + XFree(wmh); +} + +void +showhide(Client *c) +{ + if (!c) + return; + if (ISVISIBLE(c)) { + /* show clients top down */ + XMoveWindow(dpy, c->win, c->x, c->y); + if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen) + resize(c, c->x, c->y, c->w, c->h, 0); + showhide(c->snext); + } else { + /* hide clients bottom up */ + showhide(c->snext); + XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y); + } +} + +void +sigchld(int unused) +{ + if (signal(SIGCHLD, sigchld) == SIG_ERR) + die("can't install SIGCHLD handler:"); + while (0 < waitpid(-1, NULL, WNOHANG)); +} + +void +spawn(const Arg *arg) +{ + if (arg->v == dmenucmd) + dmenumon[0] = '0' + selmon->num; + if (fork() == 0) { + if (dpy) + close(ConnectionNumber(dpy)); + setsid(); + execvp(((char **)arg->v)[0], (char **)arg->v); + fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]); + perror(" failed"); + exit(EXIT_SUCCESS); + } +} + +void +tag(const Arg *arg) +{ + if (selmon->sel && arg->ui & TAGMASK) { + selmon->sel->tags = arg->ui & TAGMASK; + focus(NULL); + arrange(selmon); + } +} + +void +tagmon(const Arg *arg) +{ + if (!selmon->sel || !mons->next) + return; + sendmon(selmon->sel, dirtomon(arg->i)); +} + +void +tile(Monitor *m) +{ + unsigned int i, n, h, mw, my, ty; + Client *c; + + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if (n == 0) + return; + + if (n > m->nmaster) + mw = m->nmaster ? m->ww * m->mfact : 0; + else + mw = m->ww - m->gappx; + for (i = 0, my = ty = m->gappx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { + h = (m->wh - my) / (MIN(n, m->nmaster) - i) - m->gappx; + resize(c, m->wx + m->gappx, m->wy + my, mw - (2*c->bw) - m->gappx, h - (2*c->bw), 0); + my += HEIGHT(c) + m->gappx; + } else { + h = (m->wh - ty) / (n - i) - m->gappx; + resize(c, m->wx + mw + m->gappx, m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->gappx, h - (2*c->bw), 0); + ty += HEIGHT(c) + m->gappx; + } +} + +void +togglebar(const Arg *arg) +{ + selmon->showbar = !selmon->showbar; + updatebarpos(selmon); + 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); +} + +void +togglefloating(const Arg *arg) +{ + if (!selmon->sel) + return; + if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ + return; + selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed; + if (selmon->sel->isfloating) + resize(selmon->sel, selmon->sel->x, selmon->sel->y, + selmon->sel->w, selmon->sel->h, 0); + arrange(selmon); +} + +void +toggletag(const Arg *arg) +{ + unsigned int newtags; + + if (!selmon->sel) + return; + newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); + if (newtags) { + selmon->sel->tags = newtags; + focus(NULL); + arrange(selmon); + } +} + +void +toggleview(const Arg *arg) +{ + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + + if (newtagset) { + selmon->tagset[selmon->seltags] = newtagset; + focus(NULL); + arrange(selmon); + } +} + +void +unfocus(Client *c, int setfocus) +{ + if (!c) + return; + grabbuttons(c, 0); + XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); + if (setfocus) { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); + } +} + +void +unmanage(Client *c, int destroyed) +{ + Monitor *m = c->mon; + XWindowChanges wc; + + detach(c); + detachstack(c); + if (!destroyed) { + wc.border_width = c->oldbw; + XGrabServer(dpy); /* avoid race conditions */ + XSetErrorHandler(xerrordummy); + XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */ + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); + setclientstate(c, WithdrawnState); + XSync(dpy, False); + XSetErrorHandler(xerror); + XUngrabServer(dpy); + } + free(c); + focus(NULL); + updateclientlist(); + arrange(m); +} + +void +unmapnotify(XEvent *e) +{ + Client *c; + XUnmapEvent *ev = &e->xunmap; + + if ((c = wintoclient(ev->window))) { + if (ev->send_event) + setclientstate(c, WithdrawnState); + 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, + .background_pixmap = ParentRelative, + .event_mask = ButtonPressMask|ExposureMask + }; + XClassHint ch = {"dwm", "dwm"}; + for (m = mons; m; m = m->next) { + if (m->barwin) + continue; + 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); + } +} + +void +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; + } else + m->by = -bh; +} + +void +updateclientlist() +{ + Client *c; + Monitor *m; + + XDeleteProperty(dpy, root, netatom[NetClientList]); + for (m = mons; m; m = m->next) + for (c = m->clients; c; c = c->next) + XChangeProperty(dpy, root, netatom[NetClientList], + XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); +} + +int +updategeom(void) +{ + int dirty = 0; + +#ifdef XINERAMA + if (XineramaIsActive(dpy)) { + int i, j, n, nn; + Client *c; + Monitor *m; + XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn); + XineramaScreenInfo *unique = NULL; + + for (n = 0, m = mons; m; m = m->next, n++); + /* only consider unique geometries as separate screens */ + unique = ecalloc(nn, sizeof(XineramaScreenInfo)); + for (i = 0, j = 0; i < nn; i++) + if (isuniquegeom(unique, j, &info[i])) + memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo)); + XFree(info); + nn = j; + if (n <= nn) { /* new monitors available */ + for (i = 0; i < (nn - n); i++) { + for (m = mons; m && m->next; m = m->next); + if (m) + m->next = createmon(); + else + mons = createmon(); + } + for (i = 0, m = mons; i < nn && m; m = m->next, i++) + if (i >= n + || unique[i].x_org != m->mx || unique[i].y_org != m->my + || unique[i].width != m->mw || unique[i].height != m->mh) + { + dirty = 1; + m->num = i; + m->mx = m->wx = unique[i].x_org; + m->my = m->wy = unique[i].y_org; + m->mw = m->ww = unique[i].width; + m->mh = m->wh = unique[i].height; + updatebarpos(m); + } + } else { /* less monitors available nn < n */ + for (i = nn; i < n; i++) { + for (m = mons; m && m->next; m = m->next); + while ((c = m->clients)) { + dirty = 1; + m->clients = c->next; + detachstack(c); + c->mon = mons; + attach(c); + attachstack(c); + } + if (m == selmon) + selmon = mons; + cleanupmon(m); + } + } + free(unique); + } else +#endif /* XINERAMA */ + { /* default monitor setup */ + if (!mons) + mons = createmon(); + if (mons->mw != sw || mons->mh != sh) { + dirty = 1; + mons->mw = mons->ww = sw; + mons->mh = mons->wh = sh; + updatebarpos(mons); + } + } + if (dirty) { + selmon = mons; + selmon = wintomon(root); + } + return dirty; +} + +void +updatenumlockmask(void) +{ + unsigned int i, j; + XModifierKeymap *modmap; + + numlockmask = 0; + modmap = XGetModifierMapping(dpy); + for (i = 0; i < 8; i++) + for (j = 0; j < modmap->max_keypermod; j++) + if (modmap->modifiermap[i * modmap->max_keypermod + j] + == XKeysymToKeycode(dpy, XK_Num_Lock)) + numlockmask = (1 << i); + XFreeModifiermap(modmap); +} + +void +updatesizehints(Client *c) +{ + long msize; + XSizeHints size; + + if (!XGetWMNormalHints(dpy, c->win, &size, &msize)) + /* size is uninitialized, ensure that size.flags aren't used */ + size.flags = PSize; + if (size.flags & PBaseSize) { + c->basew = size.base_width; + c->baseh = size.base_height; + } else if (size.flags & PMinSize) { + c->basew = size.min_width; + c->baseh = size.min_height; + } else + c->basew = c->baseh = 0; + if (size.flags & PResizeInc) { + c->incw = size.width_inc; + c->inch = size.height_inc; + } else + c->incw = c->inch = 0; + if (size.flags & PMaxSize) { + c->maxw = size.max_width; + c->maxh = size.max_height; + } else + c->maxw = c->maxh = 0; + if (size.flags & PMinSize) { + c->minw = size.min_width; + c->minh = size.min_height; + } else if (size.flags & PBaseSize) { + c->minw = size.base_width; + c->minh = size.base_height; + } else + c->minw = c->minh = 0; + if (size.flags & PAspect) { + c->mina = (float)size.min_aspect.y / size.min_aspect.x; + c->maxa = (float)size.max_aspect.x / size.max_aspect.y; + } else + c->maxa = c->mina = 0.0; + c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh); +} + +void +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 +updatetitle(Client *c) +{ + if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name)) + gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name); + if (c->name[0] == '\0') /* hack to mark broken clients */ + strcpy(c->name, broken); +} + +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; +} + +void +updatewmhints(Client *c) +{ + XWMHints *wmh; + + if ((wmh = XGetWMHints(dpy, c->win))) { + if (c == selmon->sel && wmh->flags & XUrgencyHint) { + wmh->flags &= ~XUrgencyHint; + XSetWMHints(dpy, c->win, wmh); + } else + c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0; + if (wmh->flags & InputHint) + c->neverfocus = !wmh->input; + else + c->neverfocus = 0; + XFree(wmh); + } +} + +void +view(const Arg *arg) +{ + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ + if (arg->ui & TAGMASK) + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + focus(NULL); + arrange(selmon); +} + +Client * +wintoclient(Window w) +{ + Client *c; + Monitor *m; + + for (m = mons; m; m = m->next) + for (c = m->clients; c; c = c->next) + if (c->win == w) + return c; + return NULL; +} + +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) +{ + int x, y; + Client *c; + Monitor *m; + + if (w == root && getrootptr(&x, &y)) + return recttomon(x, y, 1, 1); + for (m = mons; m; m = m->next) + if (w == m->barwin) + return m; + if ((c = wintoclient(w))) + return c->mon; + return selmon; +} + +/* 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. */ +int +xerror(Display *dpy, XErrorEvent *ee) +{ + if (ee->error_code == BadWindow + || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch) + || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable) + || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable) + || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable) + || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch) + || (ee->request_code == X_GrabButton && ee->error_code == BadAccess) + || (ee->request_code == X_GrabKey && ee->error_code == BadAccess) + || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable)) + return 0; + fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n", + ee->request_code, ee->error_code); + return xerrorxlib(dpy, ee); /* may call exit */ +} + +int +xerrordummy(Display *dpy, XErrorEvent *ee) +{ + return 0; +} + +/* Startup Error handler to check if another window manager + * is already running. */ +int +xerrorstart(Display *dpy, XErrorEvent *ee) +{ + die("dwm: another window manager is already running"); + return -1; +} + +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) +{ + Client *c = selmon->sel; + + if (!selmon->lt[selmon->sellt]->arrange + || (selmon->sel && selmon->sel->isfloating)) + return; + if (c == nexttiled(selmon->clients)) + if (!c || !(c = nexttiled(c->next))) + return; + pop(c); +} + +int +main(int argc, char *argv[]) +{ + if (argc == 2 && !strcmp("-v", argv[1])) + die("dwm-"VERSION); + else if (argc != 1) + die("usage: dwm [-v]"); + if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) + fputs("warning: no locale support\n", stderr); + if (!(dpy = XOpenDisplay(NULL))) + die("dwm: cannot open display"); + checkotherwm(); + setup(); +#ifdef __OpenBSD__ + if (pledge("stdio rpath proc exec", NULL) == -1) + die("pledge"); +#endif /* __OpenBSD__ */ + scan(); + run(); + cleanup(); + XCloseDisplay(dpy); + return EXIT_SUCCESS; +} diff --git a/stuff/manual-programs/suckless/dwm-bak/dwm.o b/stuff/manual-programs/suckless/dwm-bak/dwm.o new file mode 100644 index 0000000000000000000000000000000000000000..2dd20f66a1421fedf682ac9856b88dc4d8bda5a6 GIT binary patch literal 69016 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 NnuTBU_05&m|G%N2*AoB$ literal 0 HcmV?d00001 diff --git a/stuff/manual-programs/suckless/dwm-bak/dwm.png b/stuff/manual-programs/suckless/dwm-bak/dwm.png new file mode 100644 index 0000000000000000000000000000000000000000..b1f9ba7e5f4cc7350ee2392ebcea5fcbe00fb49b GIT binary patch literal 373 zcmeAS@N?(olHy`uVBq!ia0vp^2Y@($g9*gC@m3f}u_bxCyDx`7I;J! zGca%iWx0hJ8D`Cq01C2~c>21sUt<^MF=V?Ztt9{yk}YwKC~?lu%}vcKVQ?-=O)N=G zQ7F$W$xsN%NL6t6^bL5QqM8R(c+=CxF{I+w+q;fj4F)_6j>`Z3pZ>_($QEQ&92OXP z%lpEKGwG8$G-U1H{@Y%;mx-mNK|p|siBVAj$Z~Mt-~h6K0!}~{PyozQ07(f5fTdVi zm=-zT`NweeJ#%S&{fequZGmkDDC*%x$$Sa*fAP=$`nJkhx1Y~k<8b2;Hq)FOdV=P$ q&oWzoxz_&nv&n0)xBzV8k*jsxheTIy&cCY600f?{elF{r5}E*x)opSB literal 0 HcmV?d00001 diff --git a/stuff/manual-programs/suckless/dwm-bak/dwmstatus/LICENSE b/stuff/manual-programs/suckless/dwm-bak/dwmstatus/LICENSE new file mode 100644 index 0000000..855608d --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/dwmstatus/LICENSE @@ -0,0 +1,21 @@ +MIT/X Consortium License + +© 2011-2018 Christoph Lohmann <20h@r-36.net> + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/stuff/manual-programs/suckless/dwm-bak/dwmstatus/Makefile b/stuff/manual-programs/suckless/dwm-bak/dwmstatus/Makefile new file mode 100644 index 0000000..62240a5 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/dwmstatus/Makefile @@ -0,0 +1,49 @@ +# See LICENSE file for copyright and license details. + +include config.mk + +SRC = ${NAME}.c +OBJ = ${SRC:.c=.o} + +all: options ${NAME} + +options: + @echo ${NAME} build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +.c.o: + @echo CC $< + @${CC} -c ${CFLAGS} $< + +${OBJ}: config.mk + +${NAME}: ${OBJ} + @echo CC -o $@ + @${CC} -o $@ ${OBJ} ${LDFLAGS} + +clean: + @echo cleaning + @rm -f ${NAME} ${OBJ} ${NAME}-${VERSION}.tar.gz + +dist: clean + @echo creating dist tarball + @mkdir -p ${NAME}-${VERSION} + @cp -R Makefile LICENSE config.mk \ + ${SRC} ${NAME}-${VERSION} + @tar -cf ${NAME}-${VERSION}.tar ${NAME}-${VERSION} + @gzip ${NAME}-${VERSION}.tar + @rm -rf ${NAME}-${VERSION} + +install: all + @echo installing executable file to ${DESTDIR}${PREFIX}/bin + @mkdir -p ${DESTDIR}${PREFIX}/bin + @cp -f ${NAME} ${DESTDIR}${PREFIX}/bin + @chmod 755 ${DESTDIR}${PREFIX}/bin/${NAME} + +uninstall: + @echo removing executable file from ${DESTDIR}${PREFIX}/bin + @rm -f ${DESTDIR}${PREFIX}/bin/${NAME} + +.PHONY: all options clean dist install uninstall diff --git a/stuff/manual-programs/suckless/dwm-bak/dwmstatus/config.mk b/stuff/manual-programs/suckless/dwm-bak/dwmstatus/config.mk new file mode 100644 index 0000000..0ec9e47 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/dwmstatus/config.mk @@ -0,0 +1,30 @@ +NAME = dwmstatus +VERSION = 1.0 + +# Customize below to fit your system + +# paths +PREFIX = /usr +MANPREFIX = ${PREFIX}/share/man + +X11INC = /usr/X11R6/include +X11LIB = /usr/X11R6/lib + +# includes and libs +INCS = -I. -I/usr/include -I${X11INC} +LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 + +# flags +CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE +CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} +#CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} +LDFLAGS = -g ${LIBS} +#LDFLAGS = -s ${LIBS} + +# Solaris +#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\" +#LDFLAGS = ${LIBS} + +# compiler and linker +CC = cc + diff --git a/stuff/manual-programs/suckless/dwm-bak/dwmstatus/dwmstatus-temperature.c b/stuff/manual-programs/suckless/dwm-bak/dwmstatus/dwmstatus-temperature.c new file mode 100644 index 0000000..13f27f6 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/dwmstatus/dwmstatus-temperature.c @@ -0,0 +1,15 @@ +/* + * gettemperature("/sys/class/hwmon/hwmon0/device", "temp1_input"); + */ + +char * +gettemperature(char *base, char *sensor) +{ + char *co; + + co = readfile(base, sensor); + if (co == NULL) + return smprintf(""); + return smprintf("%02.0f°C", atof(co) / 1000); +} + diff --git a/stuff/manual-programs/suckless/dwm-bak/dwmstatus/dwmstatus.c b/stuff/manual-programs/suckless/dwm-bak/dwmstatus/dwmstatus.c new file mode 100644 index 0000000..d2a4b03 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/dwmstatus/dwmstatus.c @@ -0,0 +1,227 @@ +/* + * Copy me if you can. + * by 20h + */ + +#define _BSD_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +char *tzargentina = "America/Buenos_Aires"; +char *tzutc = "UTC"; +char *tzberlin = "Europe/Berlin"; + +static Display *dpy; + +char * +smprintf(char *fmt, ...) +{ + va_list fmtargs; + char *ret; + int len; + + va_start(fmtargs, fmt); + len = vsnprintf(NULL, 0, fmt, fmtargs); + va_end(fmtargs); + + ret = malloc(++len); + if (ret == NULL) { + perror("malloc"); + exit(1); + } + + va_start(fmtargs, fmt); + vsnprintf(ret, len, fmt, fmtargs); + va_end(fmtargs); + + return ret; +} + +void +settz(char *tzname) +{ + setenv("TZ", tzname, 1); +} + +char * +mktimes(char *fmt, char *tzname) +{ + char buf[129]; + time_t tim; + struct tm *timtm; + + settz(tzname); + tim = time(NULL); + timtm = localtime(&tim); + if (timtm == NULL) + return smprintf(""); + + if (!strftime(buf, sizeof(buf)-1, fmt, timtm)) { + fprintf(stderr, "strftime == 0\n"); + return smprintf(""); + } + + return smprintf("%s", buf); +} + +void +setstatus(char *str) +{ + XStoreName(dpy, DefaultRootWindow(dpy), str); + XSync(dpy, False); +} + +char * +loadavg(void) +{ + double avgs[3]; + + if (getloadavg(avgs, 3) < 0) + return smprintf(""); + + return smprintf("%.2f %.2f %.2f", avgs[0], avgs[1], avgs[2]); +} + +char * +readfile(char *base, char *file) +{ + char *path, line[513]; + FILE *fd; + + memset(line, 0, sizeof(line)); + + path = smprintf("%s/%s", base, file); + fd = fopen(path, "r"); + free(path); + if (fd == NULL) + return NULL; + + if (fgets(line, sizeof(line)-1, fd) == NULL) + return NULL; + fclose(fd); + + return smprintf("%s", line); +} + +char * +getbattery(char *base) +{ + char *co, status; + int descap, remcap; + + descap = -1; + remcap = -1; + + co = readfile(base, "present"); + if (co == NULL) + return smprintf(""); + if (co[0] != '1') { + free(co); + return smprintf("not present"); + } + free(co); + + co = readfile(base, "charge_full_design"); + if (co == NULL) { + co = readfile(base, "energy_full_design"); + if (co == NULL) + return smprintf(""); + } + sscanf(co, "%d", &descap); + free(co); + + co = readfile(base, "charge_now"); + if (co == NULL) { + co = readfile(base, "energy_now"); + if (co == NULL) + return smprintf(""); + } + sscanf(co, "%d", &remcap); + free(co); + + co = readfile(base, "status"); + if (!strncmp(co, "Discharging", 11)) { + status = '-'; + } else if(!strncmp(co, "Charging", 8)) { + status = '+'; + } else { + status = '?'; + } + + if (remcap < 0 || descap < 0) + return smprintf("invalid"); + + return smprintf("%.0f%%%c", ((float)remcap / (float)descap) * 100, status); +} + +char * +gettemperature(char *base, char *sensor) +{ + char *co; + + co = readfile(base, sensor); + if (co == NULL) + return smprintf(""); + return smprintf("%02.0f°C", atof(co) / 1000); +} + +int +main(void) +{ + char *status; + char *avgs; + char *bat; + char *bat1; + char *tmar; + char *tmutc; + char *tmbln; + char *t0, *t1, *t2; + + if (!(dpy = XOpenDisplay(NULL))) { + fprintf(stderr, "dwmstatus: cannot open display.\n"); + return 1; + } + + for (;;sleep(60)) { + avgs = loadavg(); + bat = getbattery("/sys/class/power_supply/BAT0"); + bat1 = getbattery("/sys/class/power_supply/BAT1"); + tmar = mktimes("%H:%M", tzargentina); + tmutc = mktimes("%H:%M", tzutc); + tmbln = mktimes("KW %W %a %d %b %H:%M %Z %Y", tzberlin); + t0 = gettemperature("/sys/devices/virtual/hwmon/hwmon0", "temp1_input"); + t1 = gettemperature("/sys/devices/virtual/hwmon/hwmon2", "temp1_input"); + t2 = gettemperature("/sys/devices/virtual/hwmon/hwmon4", "temp1_input"); + + status = smprintf("T:%s|%s|%s L:%s B:%s|%s A:%s U:%s %s", + t0, t1, t2, avgs, bat, bat1, tmar, tmutc, + tmbln); + setstatus(status); + + free(t0); + free(t1); + free(t2); + free(avgs); + free(bat); + free(bat1); + free(tmar); + free(tmutc); + free(tmbln); + free(status); + } + + XCloseDisplay(dpy); + + return 0; +} + diff --git a/stuff/manual-programs/suckless/dwm-bak/dwmstatus/new-acpi-battery.c b/stuff/manual-programs/suckless/dwm-bak/dwmstatus/new-acpi-battery.c new file mode 100644 index 0000000..cda0084 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/dwmstatus/new-acpi-battery.c @@ -0,0 +1,55 @@ +char * +readfile(char *base, char *file) +{ + char *path, line[513]; + FILE *fd; + + memset(line, 0, sizeof(line)); + + path = smprintf("%s/%s", base, file); + fd = fopen(path, "r"); + if (fd == NULL) { + perror("fopen"); + exit(1); + } + free(path); + + if (fgets(line, sizeof(line)-1, fd) == NULL) { + perror("fgets"); + exit(1); + } + fclose(fd); + + return smprintf("%s", line); +} + +char * +getbattery(char *base) +{ + char *co; + int descap, remcap; + + descap = -1; + remcap = -1; + + co = readfile(base, "present"); + if (co[0] != '1') { + free(co); + return smprintf("not present"); + } + free(co); + + co = readfile(base, "charge_full_design"); + sscanf(co, "%d", &descap); + free(co); + + co = readfile(base, "charge_now"); + sscanf(co, "%d", &remcap); + free(co); + + if (remcap < 0 || descap < 0) + return smprintf("invalid"); + + return smprintf("%.0f", ((float)remcap / (float)descap) * 100); +} + diff --git a/stuff/manual-programs/suckless/dwm-bak/endx b/stuff/manual-programs/suckless/dwm-bak/endx new file mode 100644 index 0000000..982d44f --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/endx @@ -0,0 +1,5 @@ +#!/bin/sh +#gives you a dmenu prompt to confirm if you want to exit X + +[ $(echo -e "No\nYes" | dmenu -i -p "$1") \ +== "Yes" ] && $2 diff --git a/stuff/manual-programs/suckless/dwm-bak/shiftview.c b/stuff/manual-programs/suckless/dwm-bak/shiftview.c new file mode 100644 index 0000000..e82053a --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/shiftview.c @@ -0,0 +1,19 @@ +/** 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/stuff/manual-programs/suckless/dwm-bak/transient.c b/stuff/manual-programs/suckless/dwm-bak/transient.c new file mode 100644 index 0000000..040adb5 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/transient.c @@ -0,0 +1,42 @@ +/* cc transient.c -o transient -lX11 */ + +#include +#include +#include +#include + +int main(void) { + Display *d; + Window r, f, t = None; + XSizeHints h; + XEvent e; + + d = XOpenDisplay(NULL); + if (!d) + exit(1); + r = DefaultRootWindow(d); + + f = XCreateSimpleWindow(d, r, 100, 100, 400, 400, 0, 0, 0); + h.min_width = h.max_width = h.min_height = h.max_height = 400; + h.flags = PMinSize | PMaxSize; + XSetWMNormalHints(d, f, &h); + XStoreName(d, f, "floating"); + XMapWindow(d, f); + + XSelectInput(d, f, ExposureMask); + while (1) { + XNextEvent(d, &e); + + if (t == None) { + sleep(5); + t = XCreateSimpleWindow(d, r, 50, 50, 100, 100, 0, 0, 0); + XSetTransientForHint(d, t, f); + XStoreName(d, t, "transient"); + XMapWindow(d, t); + XSelectInput(d, t, ExposureMask); + } + } + + XCloseDisplay(d); + exit(0); +} diff --git a/stuff/manual-programs/suckless/dwm-bak/util.c b/stuff/manual-programs/suckless/dwm-bak/util.c new file mode 100644 index 0000000..fe044fc --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/util.c @@ -0,0 +1,35 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include + +#include "util.h" + +void * +ecalloc(size_t nmemb, size_t size) +{ + void *p; + + if (!(p = calloc(nmemb, size))) + die("calloc:"); + return p; +} + +void +die(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + if (fmt[0] && fmt[strlen(fmt)-1] == ':') { + fputc(' ', stderr); + perror(NULL); + } else { + fputc('\n', stderr); + } + + exit(1); +} diff --git a/stuff/manual-programs/suckless/dwm-bak/util.h b/stuff/manual-programs/suckless/dwm-bak/util.h new file mode 100644 index 0000000..f633b51 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm-bak/util.h @@ -0,0 +1,8 @@ +/* See LICENSE file for copyright and license details. */ + +#define MAX(A, B) ((A) > (B) ? (A) : (B)) +#define MIN(A, B) ((A) < (B) ? (A) : (B)) +#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B)) + +void die(const char *fmt, ...); +void *ecalloc(size_t nmemb, size_t size); diff --git a/stuff/manual-programs/suckless/dwm-bak/util.o b/stuff/manual-programs/suckless/dwm-bak/util.o new file mode 100644 index 0000000000000000000000000000000000000000..8e55fa18d6ada0bfba70d02362b40ffaf2d35ebf GIT binary patch literal 2224 zcmbtUO=uHQ5T0$TjWtbT?V(Z+5mrf{E}Ik~q$<%yyGoE+D{3#ACR-cKpPNldRWM>b zgb?V#qX!Qj6g(94C^YE7t4B}Pqfig^ASe~$%?e!*H_wR z+#gQLxBTIhT=s{b%5|js!_VYZOTUnxTl%%UX6d(b+tTmkPpGq6v+rmK4Gjy1B5kdC z3LW&mXss1_iv>os)~p=RT1i>`n3Mw^gi#NxEFAoX2Gl1&Yn~v>9Mc*b)Ud}2Xic>0 z4|+TC>cRCO#w|3`vDD_k`T&R4>1-_YvYq&(UG-`$t0N1T`;bZJ^QBB2U}|zQ9t=%g zx*85f#+9fN2}afExEfO#KRRyF-kt7tqjojnaLGz| z^@i91Tmi-r6@7;rexwT?>Vhj>aGJVXeVmikC-2WXC&VVY@S$qv@=6Aj)T9d8oDLN; zs~ZL^EtHL1(Of{^$m>N|C|Au4lrdB?K(FOY(Cv$XbxEqW!nxab;7`YvR}81SuooA{ z-!RcV5AE=@9h6{5Yy=>Xttsx zm@~xAiN_o+jADS!FTn{+*XXcOJS<^9+GN`A)BaCT{20R-oghnQoEtIR36CL8HUBlA z{(V$4ic1u}Kkt{v`2JicFhDl_*hQIR1pY7NF`mcu1q^VTb4V|_fiBz|h|xO}?<%@b zWBJa$oZoX7xkPp5zhwE-R7? +© 2006-2009 Jukka Salmi +© 2006-2007 Sander van Dijk +© 2007-2011 Peter Hartlich +© 2007-2009 Szabolcs Nagy +© 2007-2009 Christof Musik +© 2007-2009 Premysl Hruby +© 2007-2008 Enno Gottox Boland +© 2008 Martin Hurton +© 2008 Neale Pickett +© 2009 Mate Nagy +© 2010-2016 Hiltjo Posthuma +© 2010-2012 Connor Lane Smith +© 2011 Christoph Lohmann <20h@r-36.net> +© 2015-2016 Quentin Rameau +© 2015-2016 Eric Pruitt +© 2016-2017 Markus Teich + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/stuff/manual-programs/suckless/dwm/Makefile b/stuff/manual-programs/suckless/dwm/Makefile new file mode 100644 index 0000000..77bcbc0 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/Makefile @@ -0,0 +1,51 @@ +# dwm - dynamic window manager +# See LICENSE file for copyright and license details. + +include config.mk + +SRC = drw.c dwm.c util.c +OBJ = ${SRC:.c=.o} + +all: options dwm + +options: + @echo dwm build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +.c.o: + ${CC} -c ${CFLAGS} $< + +${OBJ}: config.h config.mk + +config.h: + cp config.def.h $@ + +dwm: ${OBJ} + ${CC} -o $@ ${OBJ} ${LDFLAGS} + +clean: + rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz + +dist: clean + mkdir -p dwm-${VERSION} + cp -R LICENSE Makefile README config.def.h config.mk\ + dwm.1 drw.h util.h ${SRC} dwm.png transient.c dwm-${VERSION} + tar -cf dwm-${VERSION}.tar dwm-${VERSION} + gzip dwm-${VERSION}.tar + rm -rf dwm-${VERSION} + +install: all + mkdir -p ${DESTDIR}${PREFIX}/bin + cp -f dwm ${DESTDIR}${PREFIX}/bin + chmod 755 ${DESTDIR}${PREFIX}/bin/dwm + mkdir -p ${DESTDIR}${MANPREFIX}/man1 + sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1 + chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1 + +uninstall: + rm -f ${DESTDIR}${PREFIX}/bin/dwm\ + ${DESTDIR}${MANPREFIX}/man1/dwm.1 + +.PHONY: all options clean dist install uninstall diff --git a/stuff/manual-programs/suckless/dwm/README b/stuff/manual-programs/suckless/dwm/README new file mode 100644 index 0000000..95d4fd0 --- /dev/null +++ b/stuff/manual-programs/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/stuff/manual-programs/suckless/dwm/awesome-glyphs.txt b/stuff/manual-programs/suckless/dwm/awesome-glyphs.txt new file mode 100644 index 0000000..7541568 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/awesome-glyphs.txt @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/stuff/manual-programs/suckless/dwm/config.def.h.orig b/stuff/manual-programs/suckless/dwm/config.def.h.orig new file mode 100644 index 0000000..c9b7665 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/config.def.h.orig @@ -0,0 +1,146 @@ +/* See LICENSE file for copyright and license details. */ + +/* appearance */ +static const unsigned int borderpx = 2; /* border pixel size of windows */ +static const unsigned int gappx = 5; /* gaps size between 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 = 0; /* 0 means bottom bar */ +static const char *fonts[] = { "monospace:size=12", "fontawesome:size=12" }; +static const char dmenufont[] = "monospace:size=11"; +//background color +static const char col_gray1[] = "#222222"; +//inactive window border color +static const char col_gray2[] = "#444444"; +//font color +static const char col_gray3[] = "#bbbbbb"; +//current tag and current window font color +static const char col_gray4[] = "#eeeeee"; +//Top bar second color (blue) and active window border color +static const char col_cyan[] = "#8558e6"; +static const char *colors[][3] = { + /* fg bg border */ + [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, + [SchemeSel] = { col_gray4, col_cyan, col_cyan }, +}; + +/* tagging */ +//tag names (upper left) +static const char *tags[] = { "", "", "", "", "", "", "", "", "", "" }; + +static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ + /* class instance title tags mask isfloating monitor */ + { "Gimp", NULL, NULL, 0, 1, -1 }, + { "Firefox", NULL, NULL, 1 << 8, 1, -1 }, +}; + +/* layout(s) */ +static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ +static const int nmaster = 1; /* number of clients in master area */ +static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ + +static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, +}; + +/* 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 } } + +/* commands */ +static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ +static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; +//static const char *filemanager[] = { " +//launches htop +static const char *monitor[] = { "/usr/bin/htop", NULL }; +//sets st as the default terminal +//static const char *termcmd[] = { "st", NULL }; +//sets urxvt as the default terminal +static const char *termcmd[] = { "urxvt", NULL }; +//volume controls +static const char *upvol[] = { "amixer", "-q", "set", "Master", "5%+", "unmute", NULL }; +static const char *downvol[] = { "amixer", "-q", "set", "Master", "5%-", "unmute", NULL }; +static const char *mutevol[] = { "amixer", "-q", "set", "Master", "toggle", NULL }; + +#include "shiftview.c" +static char *endx[] = { "/bin/sh", "-c", "endx", "externalpipe", NULL }; +static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_d, spawn, {.v = dmenucmd } }, + { MODKEY, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_t, togglebar, {0} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, + { MODKEY, XK_u, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, + { MODKEY, XK_z, zoom, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY, XK_q, killclient, {0} }, + { MODKEY|ShiftMask, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY|ShiftMask, XK_f, setlayout, {.v = &layouts[1]} }, + { MODKEY|ShiftMask, XK_m, setlayout, {.v = &layouts[2]} }, + { MODKEY|ShiftMask, XK_space, setlayout, {0} }, + { MODKEY, XK_space, togglefloating, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, + { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, + { MODKEY, XK_comma, focusmon, {.i = -1 } }, + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY, XK_minus, setgaps, {.i = -1 } }, + { MODKEY, XK_equal, setgaps, {.i = +1 } }, + { MODKEY|ShiftMask, XK_equal, setgaps, {.i = 0 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + { MODKEY, XK_n, shiftview, { .i = +1 } }, + { MODKEY, XK_b, shiftview, { .i = -1 } }, + { MODKEY, XK_F8, spawn, {.v = upvol } }, + { MODKEY, XK_F7, spawn, {.v = downvol } }, + { MODKEY, XK_F5, spawn, {.v = mutevol } }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) + TAGKEYS( XK_4, 3) + TAGKEYS( XK_5, 4) + TAGKEYS( XK_6, 5) + TAGKEYS( XK_7, 6) + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) + { MODKEY|ShiftMask, XK_q, quit, {0} }, +}; + +/* button definitions */ +/* 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} }, +}; + diff --git a/stuff/manual-programs/suckless/dwm/config.h b/stuff/manual-programs/suckless/dwm/config.h new file mode 100644 index 0000000..6d75362 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/config.h @@ -0,0 +1,151 @@ +/* See LICENSE file for copyright and license details. */ + +/* appearance */ +static const unsigned int borderpx = 2; /* border pixel size of windows */ +static const unsigned int gappx = 5; /* gaps size between 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 = 0; /* 0 means bottom bar */ +static const char *fonts[] = { "monospace:size=11", "fontawesome:size=11" }; +static const char dmenufont[] = "monospace:size=10"; +//background color +static const char col_gray1[] = "#222222"; +//inactive window border color +static const char col_gray2[] = "#444444"; +//font color +static const char col_gray3[] = "#bbbbbb"; +//current tag and current window font color +static const char col_gray4[] = "#eeeeee"; +//Top bar second color (blue) and active window border color +static const char col_cyan[] = "#8558e6"; +static const char *colors[][3] = { + /* fg bg border */ + [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, + [SchemeSel] = { col_gray4, col_cyan, col_cyan }, +}; + +/* tagging */ +//tag names (upper left) +static const char *tags[] = { "", "", "", "", "", "", "", "", "", "" }; + +static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ + /* class instance title tags mask isfloating monitor */ + { "Gimp", NULL, NULL, 0, 1, -1 }, + { "Firefox", NULL, NULL, 1 << 8, 1, -1 }, +}; + +/* layout(s) */ +static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ +static const int nmaster = 1; /* number of clients in master area */ +static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ + +static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, + { "TTT", bstack }, + { "===", bstackhoriz }, +}; + +/* 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 } } + +/* commands */ +static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ +//static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; +static const char *dmenucmd[] = { "rofi", "-show", "drun"}; +//static const char *filemanager[] = { " +//launches htop +static const char *monitor[] = { "/usr/bin/htop", NULL }; +//sets st as the default terminal +//static const char *termcmd[] = { "st", NULL }; +//sets urxvt as the default terminal +static const char *termcmd[] = { "wezterm", NULL }; +//volume controls +static const char *upvol[] = { "amixer", "-q", "set", "Master", "5%+", "unmute", NULL }; +static const char *downvol[] = { "amixer", "-q", "set", "Master", "5%-", "unmute", NULL }; +static const char *mutevol[] = { "amixer", "-q", "set", "Master", "toggle", NULL }; + +#include "shiftview.c" +static char *endx[] = { "/bin/sh", "-c", "endx", "externalpipe", NULL }; +static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_d, spawn, {.v = dmenucmd } }, + { MODKEY, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_t, togglebar, {0} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, + { MODKEY, XK_u, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, + { MODKEY, XK_z, zoom, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY, XK_q, killclient, {0} }, + { MODKEY|ShiftMask, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY|ShiftMask, XK_f, setlayout, {.v = &layouts[1]} }, + { MODKEY|ShiftMask, XK_m, setlayout, {.v = &layouts[2]} }, + { MODKEY|ShiftMask, XK_u, setlayout, {.v = &layouts[3]} }, + { MODKEY|ShiftMask, XK_o, setlayout, {.v = &layouts[4]} }, + { MODKEY|ShiftMask, XK_space, setlayout, {0} }, + { MODKEY, XK_space, togglefloating, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, + { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, + { MODKEY, XK_comma, focusmon, {.i = -1 } }, + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY, XK_minus, setgaps, {.i = -1 } }, + { MODKEY, XK_equal, setgaps, {.i = +1 } }, + { MODKEY|ShiftMask, XK_equal, setgaps, {.i = 0 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + { MODKEY, XK_n, shiftview, { .i = +1 } }, + { MODKEY, XK_b, shiftview, { .i = -1 } }, + { MODKEY, XK_F8, spawn, {.v = upvol } }, + { MODKEY, XK_F7, spawn, {.v = downvol } }, + { MODKEY, XK_F5, spawn, {.v = mutevol } }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) + TAGKEYS( XK_4, 3) + TAGKEYS( XK_5, 4) + TAGKEYS( XK_6, 5) + TAGKEYS( XK_7, 6) + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) + { MODKEY|ShiftMask, XK_q, quit, {0} }, +}; + +/* button definitions */ +/* 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} }, +}; + diff --git a/stuff/manual-programs/suckless/dwm/config.mk b/stuff/manual-programs/suckless/dwm/config.mk new file mode 100644 index 0000000..6d36cb7 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/config.mk @@ -0,0 +1,38 @@ +# dwm version +VERSION = 6.2 + +# Customize below to fit your system + +# paths +PREFIX = /usr/local +MANPREFIX = ${PREFIX}/share/man + +X11INC = /usr/X11R6/include +X11LIB = /usr/X11R6/lib + +# Xinerama, comment if you don't want it +XINERAMALIBS = -lXinerama +XINERAMAFLAGS = -DXINERAMA + +# freetype +FREETYPELIBS = -lfontconfig -lXft +FREETYPEINC = /usr/include/freetype2 +# OpenBSD (uncomment) +#FREETYPEINC = ${X11INC}/freetype2 + +# includes and libs +INCS = -I${X11INC} -I${FREETYPEINC} +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} + +# flags +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +#CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} +CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS} +LDFLAGS = ${LIBS} + +# Solaris +#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\" +#LDFLAGS = ${LIBS} + +# compiler and linker +CC = cc diff --git a/stuff/manual-programs/suckless/dwm/drw.c b/stuff/manual-programs/suckless/dwm/drw.c new file mode 100644 index 0000000..8fd1ca4 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/drw.c @@ -0,0 +1,435 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include + +#include "drw.h" +#include "util.h" + +#define UTF_INVALID 0xFFFD +#define UTF_SIZ 4 + +static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; +static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; +static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; +static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; + +static long +utf8decodebyte(const char c, size_t *i) +{ + for (*i = 0; *i < (UTF_SIZ + 1); ++(*i)) + if (((unsigned char)c & utfmask[*i]) == utfbyte[*i]) + return (unsigned char)c & ~utfmask[*i]; + return 0; +} + +static size_t +utf8validate(long *u, size_t i) +{ + if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) + *u = UTF_INVALID; + for (i = 1; *u > utfmax[i]; ++i) + ; + return i; +} + +static size_t +utf8decode(const char *c, long *u, size_t clen) +{ + size_t i, j, len, type; + long udecoded; + + *u = UTF_INVALID; + if (!clen) + return 0; + udecoded = utf8decodebyte(c[0], &len); + if (!BETWEEN(len, 1, UTF_SIZ)) + return 1; + for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { + udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); + if (type) + return j; + } + if (j < len) + return 0; + *u = udecoded; + utf8validate(u, len); + + return len; +} + +Drw * +drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h) +{ + Drw *drw = ecalloc(1, sizeof(Drw)); + + drw->dpy = dpy; + drw->screen = screen; + drw->root = root; + drw->w = w; + drw->h = h; + drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); + drw->gc = XCreateGC(dpy, root, 0, NULL); + XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); + + return drw; +} + +void +drw_resize(Drw *drw, unsigned int w, unsigned int h) +{ + if (!drw) + return; + + drw->w = w; + drw->h = h; + if (drw->drawable) + XFreePixmap(drw->dpy, drw->drawable); + drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen)); +} + +void +drw_free(Drw *drw) +{ + XFreePixmap(drw->dpy, drw->drawable); + XFreeGC(drw->dpy, drw->gc); + free(drw); +} + +/* This function is an implementation detail. Library users should use + * drw_fontset_create instead. + */ +static Fnt * +xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) +{ + Fnt *font; + XftFont *xfont = NULL; + FcPattern *pattern = NULL; + + if (fontname) { + /* Using the pattern found at font->xfont->pattern does not yield the + * same substitution results as using the pattern returned by + * FcNameParse; using the latter results in the desired fallback + * behaviour whereas the former just results in missing-character + * rectangles being drawn, at least with some fonts. */ + if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) { + fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname); + return NULL; + } + if (!(pattern = FcNameParse((FcChar8 *) fontname))) { + fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname); + XftFontClose(drw->dpy, xfont); + return NULL; + } + } else if (fontpattern) { + if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) { + fprintf(stderr, "error, cannot load font from pattern.\n"); + return NULL; + } + } else { + die("no font specified."); + } + + /* Do not allow using color fonts. This is a workaround for a BadLength + * error from Xft with color glyphs. Modelled on the Xterm workaround. See + * https://bugzilla.redhat.com/show_bug.cgi?id=1498269 + * https://lists.suckless.org/dev/1701/30932.html + * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916349 + * and lots more all over the internet. + */ + FcBool iscol; + if(FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) { + XftFontClose(drw->dpy, xfont); + return NULL; + } + + font = ecalloc(1, sizeof(Fnt)); + font->xfont = xfont; + font->pattern = pattern; + font->h = xfont->ascent + xfont->descent; + font->dpy = drw->dpy; + + return font; +} + +static void +xfont_free(Fnt *font) +{ + if (!font) + return; + if (font->pattern) + FcPatternDestroy(font->pattern); + XftFontClose(font->dpy, font->xfont); + free(font); +} + +Fnt* +drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount) +{ + Fnt *cur, *ret = NULL; + size_t i; + + if (!drw || !fonts) + return NULL; + + for (i = 1; i <= fontcount; i++) { + if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) { + cur->next = ret; + ret = cur; + } + } + return (drw->fonts = ret); +} + +void +drw_fontset_free(Fnt *font) +{ + if (font) { + drw_fontset_free(font->next); + xfont_free(font); + } +} + +void +drw_clr_create(Drw *drw, Clr *dest, const char *clrname) +{ + if (!drw || !dest || !clrname) + return; + + if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen), + DefaultColormap(drw->dpy, drw->screen), + clrname, dest)) + die("error, cannot allocate color '%s'", clrname); +} + +/* Wrapper to create color schemes. The caller has to call free(3) on the + * returned color scheme when done using it. */ +Clr * +drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) +{ + size_t i; + Clr *ret; + + /* need at least two colors for a scheme */ + if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor)))) + return NULL; + + for (i = 0; i < clrcount; i++) + drw_clr_create(drw, &ret[i], clrnames[i]); + return ret; +} + +void +drw_setfontset(Drw *drw, Fnt *set) +{ + if (drw) + drw->fonts = set; +} + +void +drw_setscheme(Drw *drw, Clr *scm) +{ + if (drw) + drw->scheme = scm; +} + +void +drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert) +{ + if (!drw || !drw->scheme) + return; + XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel); + if (filled) + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); + else + XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1); +} + +int +drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert) +{ + char buf[1024]; + int ty; + unsigned int ew; + XftDraw *d = NULL; + Fnt *usedfont, *curfont, *nextfont; + size_t i, len; + int utf8strlen, utf8charlen, render = x || y || w || h; + long utf8codepoint = 0; + const char *utf8str; + FcCharSet *fccharset; + FcPattern *fcpattern; + FcPattern *match; + XftResult result; + int charexists = 0; + + if (!drw || (render && !drw->scheme) || !text || !drw->fonts) + return 0; + + if (!render) { + w = ~w; + } else { + XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); + d = XftDrawCreate(drw->dpy, drw->drawable, + DefaultVisual(drw->dpy, drw->screen), + DefaultColormap(drw->dpy, drw->screen)); + x += lpad; + w -= lpad; + } + + usedfont = drw->fonts; + while (1) { + utf8strlen = 0; + utf8str = text; + nextfont = NULL; + while (*text) { + utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); + for (curfont = drw->fonts; curfont; curfont = curfont->next) { + charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); + if (charexists) { + if (curfont == usedfont) { + utf8strlen += utf8charlen; + text += utf8charlen; + } else { + nextfont = curfont; + } + break; + } + } + + if (!charexists || nextfont) + break; + else + charexists = 0; + } + + if (utf8strlen) { + drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL); + /* shorten text if necessary */ + for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--) + drw_font_getexts(usedfont, utf8str, len, &ew, NULL); + + if (len) { + memcpy(buf, utf8str, len); + buf[len] = '\0'; + if (len < utf8strlen) + for (i = len; i && i > len - 3; buf[--i] = '.') + ; /* NOP */ + + if (render) { + ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; + XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], + usedfont->xfont, x, ty, (XftChar8 *)buf, len); + } + x += ew; + w -= ew; + } + } + + if (!*text) { + break; + } else if (nextfont) { + charexists = 0; + usedfont = nextfont; + } else { + /* Regardless of whether or not a fallback font is found, the + * character must be drawn. */ + charexists = 1; + + fccharset = FcCharSetCreate(); + FcCharSetAddChar(fccharset, utf8codepoint); + + if (!drw->fonts->pattern) { + /* Refer to the comment in xfont_create for more information. */ + die("the first font in the cache must be loaded from a font string."); + } + + fcpattern = FcPatternDuplicate(drw->fonts->pattern); + FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); + FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); + FcPatternAddBool(fcpattern, FC_COLOR, FcFalse); + + FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); + FcDefaultSubstitute(fcpattern); + match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result); + + FcCharSetDestroy(fccharset); + FcPatternDestroy(fcpattern); + + if (match) { + usedfont = xfont_create(drw, NULL, match); + if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) { + for (curfont = drw->fonts; curfont->next; curfont = curfont->next) + ; /* NOP */ + curfont->next = usedfont; + } else { + xfont_free(usedfont); + usedfont = drw->fonts; + } + } + } + } + if (d) + XftDrawDestroy(d); + + return x + (render ? w : 0); +} + +void +drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) +{ + if (!drw) + return; + + XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y); + XSync(drw->dpy, False); +} + +unsigned int +drw_fontset_getwidth(Drw *drw, const char *text) +{ + if (!drw || !drw->fonts || !text) + return 0; + return drw_text(drw, 0, 0, 0, 0, 0, text, 0); +} + +void +drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h) +{ + XGlyphInfo ext; + + if (!font || !text) + return; + + XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext); + if (w) + *w = ext.xOff; + if (h) + *h = font->h; +} + +Cur * +drw_cur_create(Drw *drw, int shape) +{ + Cur *cur; + + if (!drw || !(cur = ecalloc(1, sizeof(Cur)))) + return NULL; + + cur->cursor = XCreateFontCursor(drw->dpy, shape); + + return cur; +} + +void +drw_cur_free(Drw *drw, Cur *cursor) +{ + if (!cursor) + return; + + XFreeCursor(drw->dpy, cursor->cursor); + free(cursor); +} diff --git a/stuff/manual-programs/suckless/dwm/drw.h b/stuff/manual-programs/suckless/dwm/drw.h new file mode 100644 index 0000000..4bcd5ad --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/drw.h @@ -0,0 +1,57 @@ +/* See LICENSE file for copyright and license details. */ + +typedef struct { + Cursor cursor; +} Cur; + +typedef struct Fnt { + Display *dpy; + unsigned int h; + XftFont *xfont; + FcPattern *pattern; + struct Fnt *next; +} Fnt; + +enum { ColFg, ColBg, ColBorder }; /* Clr scheme index */ +typedef XftColor Clr; + +typedef struct { + unsigned int w, h; + Display *dpy; + int screen; + Window root; + Drawable drawable; + GC gc; + Clr *scheme; + Fnt *fonts; +} Drw; + +/* Drawable abstraction */ +Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h); +void drw_resize(Drw *drw, unsigned int w, unsigned int h); +void drw_free(Drw *drw); + +/* Fnt abstraction */ +Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount); +void drw_fontset_free(Fnt* set); +unsigned int drw_fontset_getwidth(Drw *drw, const char *text); +void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h); + +/* Colorscheme abstraction */ +void drw_clr_create(Drw *drw, Clr *dest, const char *clrname); +Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount); + +/* Cursor abstraction */ +Cur *drw_cur_create(Drw *drw, int shape); +void drw_cur_free(Drw *drw, Cur *cursor); + +/* Drawing context manipulation */ +void drw_setfontset(Drw *drw, Fnt *set); +void drw_setscheme(Drw *drw, Clr *scm); + +/* Drawing functions */ +void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert); +int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert); + +/* Map functions */ +void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); diff --git a/stuff/manual-programs/suckless/dwm/drw.o b/stuff/manual-programs/suckless/dwm/drw.o new file mode 100644 index 0000000000000000000000000000000000000000..ec6e29f6a1e9f512a976504577dbc680474d045f GIT binary patch literal 10408 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 Uri&ul?h1;RQFLAtPj~KT~DF6Tf literal 0 HcmV?d00001 diff --git a/stuff/manual-programs/suckless/dwm/dwm b/stuff/manual-programs/suckless/dwm/dwm new file mode 100644 index 0000000000000000000000000000000000000000..705dfb9c9a8fca70076237db04b2af30de6ab0a3 GIT binary patch literal 74704 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 y9>7ioy8(YvZs~u=g0p2&hcBTQAaFcE&Y5vYx +Date: Thu Dec 22 17:31:07 2016 +0100 + + Applied and fixed autostart patch for previous version; + +diff --git a/dwm.c b/dwm.c +index d27cb67..066ed71 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -194,6 +194,7 @@ static void resizeclient(Client *c, int x, int y, int w, int h); + static void resizemouse(const Arg *arg); + static void restack(Monitor *m); + static void run(void); ++static void runAutostart(void); + static void scan(void); + static int sendevent(Client *c, Atom proto); + static void sendmon(Client *c, Monitor *m); +@@ -1386,6 +1387,12 @@ run(void) + } + + void ++runAutostart(void) { ++ system("cd ~/.dwm; ./autostart_blocking.sh"); ++ system("cd ~/.dwm; ./autostart.sh &"); ++} ++ ++void + scan(void) + { + unsigned int i, num; +@@ -2145,6 +2152,7 @@ main(int argc, char *argv[]) + checkotherwm(); + setup(); + scan(); ++ runAutostart(); + run(); + cleanup(); + XCloseDisplay(dpy); diff --git a/stuff/manual-programs/suckless/dwm/dwm-bottomstack-6.1.diff b/stuff/manual-programs/suckless/dwm/dwm-bottomstack-6.1.diff new file mode 100644 index 0000000..9fdffd5 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/dwm-bottomstack-6.1.diff @@ -0,0 +1,101 @@ +diff --git a/config.def.h b/config.def.h +index 7054c06..554f1db 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 }, ++ { "TTT", bstack }, ++ { "===", bstackhoriz }, + }; + + /* 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..c313b5e 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 bstack(Monitor *m); ++static void bstackhoriz(Monitor *m); + + /* variables */ + static const char broken[] = "broken"; +@@ -2139,3 +2141,65 @@ main(int argc, char *argv[]) + XCloseDisplay(dpy); + return EXIT_SUCCESS; + } ++ ++static void ++bstack(Monitor *m) { ++ int w, h, mh, mx, tx, ty, tw; ++ unsigned int i, n; ++ Client *c; ++ ++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); ++ if (n == 0) ++ return; ++ if (n > m->nmaster) { ++ mh = m->nmaster ? m->mfact * m->wh : 0; ++ tw = m->ww / (n - m->nmaster); ++ ty = m->wy + mh; ++ } else { ++ mh = m->wh; ++ tw = m->ww; ++ ty = m->wy; ++ } ++ for (i = mx = 0, tx = m->wx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { ++ if (i < m->nmaster) { ++ w = (m->ww - mx) / (MIN(n, m->nmaster) - i); ++ resize(c, m->wx + mx, m->wy, w - (2 * c->bw), mh - (2 * c->bw), 0); ++ mx += WIDTH(c); ++ } else { ++ h = m->wh - mh; ++ resize(c, tx, ty, tw - (2 * c->bw), h - (2 * c->bw), 0); ++ if (tw != m->ww) ++ tx += WIDTH(c); ++ } ++ } ++} ++ ++static void ++bstackhoriz(Monitor *m) { ++ int w, mh, mx, tx, ty, th; ++ unsigned int i, n; ++ Client *c; ++ ++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); ++ if (n == 0) ++ return; ++ if (n > m->nmaster) { ++ mh = m->nmaster ? m->mfact * m->wh : 0; ++ th = (m->wh - mh) / (n - m->nmaster); ++ ty = m->wy + mh; ++ } else { ++ th = mh = m->wh; ++ ty = m->wy; ++ } ++ for (i = mx = 0, tx = m->wx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { ++ if (i < m->nmaster) { ++ w = (m->ww - mx) / (MIN(n, m->nmaster) - i); ++ resize(c, m->wx + mx, m->wy, w - (2 * c->bw), mh - (2 * c->bw), 0); ++ mx += WIDTH(c); ++ } else { ++ resize(c, tx, ty, m->ww - (2 * c->bw), th - (2 * c->bw), 0); ++ if (th != m->wh) ++ ty += HEIGHT(c); ++ } ++ } ++} diff --git a/stuff/manual-programs/suckless/dwm/dwm-fullgaps-6.2.diff b/stuff/manual-programs/suckless/dwm/dwm-fullgaps-6.2.diff new file mode 100644 index 0000000..7206aec --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/dwm-fullgaps-6.2.diff @@ -0,0 +1,95 @@ +diff --git a/config.def.h b/config.def.h +index 1c0b587..38d2f6c 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 = 5; /* gaps between windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ +@@ -84,6 +85,9 @@ static Key keys[] = { + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, ++ { MODKEY, XK_minus, setgaps, {.i = -1 } }, ++ { MODKEY, XK_equal, setgaps, {.i = +1 } }, ++ { MODKEY|ShiftMask, XK_equal, setgaps, {.i = 0 } }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) +diff --git a/dwm.c b/dwm.c +index 4465af1..4363627 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -119,6 +119,7 @@ struct Monitor { + int by; /* bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ ++ int gappx; /* gaps between windows */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; +@@ -199,6 +200,7 @@ static void sendmon(Client *c, Monitor *m); + static void setclientstate(Client *c, long state); + static void setfocus(Client *c); + static void setfullscreen(Client *c, int fullscreen); ++static void setgaps(const Arg *arg); + static void setlayout(const Arg *arg); + static void setmfact(const Arg *arg); + static void setup(void); +@@ -638,6 +640,7 @@ createmon(void) + m->nmaster = nmaster; + m->showbar = showbar; + m->topbar = topbar; ++ m->gappx = gappx; + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); +@@ -1497,6 +1500,16 @@ setfullscreen(Client *c, int fullscreen) + } + } + ++void ++setgaps(const Arg *arg) ++{ ++ if ((arg->i == 0) || (selmon->gappx + arg->i < 0)) ++ selmon->gappx = 0; ++ else ++ selmon->gappx += arg->i; ++ arrange(selmon); ++} ++ + void + setlayout(const Arg *arg) + { +@@ -1683,16 +1696,16 @@ tile(Monitor *m) + if (n > m->nmaster) + mw = m->nmaster ? m->ww * m->mfact : 0; + else +- mw = m->ww; +- for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ mw = m->ww - m->gappx; ++ for (i = 0, my = ty = m->gappx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { +- h = (m->wh - my) / (MIN(n, m->nmaster) - i); +- resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); +- my += HEIGHT(c); ++ h = (m->wh - my) / (MIN(n, m->nmaster) - i) - m->gappx; ++ resize(c, m->wx + m->gappx, m->wy + my, mw - (2*c->bw) - m->gappx, h - (2*c->bw), 0); ++ my += HEIGHT(c) + m->gappx; + } 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); +- ty += HEIGHT(c); ++ h = (m->wh - ty) / (n - i) - m->gappx; ++ resize(c, m->wx + mw + m->gappx, m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->gappx, h - (2*c->bw), 0); ++ ty += HEIGHT(c) + m->gappx; + } + } + +-- +2.20.1 + diff --git a/stuff/manual-programs/suckless/dwm/dwm-systray-6.2.diff b/stuff/manual-programs/suckless/dwm/dwm-systray-6.2.diff new file mode 100644 index 0000000..27187ac --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/dwm-systray-6.2.diff @@ -0,0 +1,746 @@ +From 4001ccae7b1a41bdcb247b0cf095a51af7b68c28 Mon Sep 17 00:00:00 2001 +From: Igor Gevka +Date: Sun, 16 Feb 2020 15:03:10 -0800 +Subject: [PATCH] [PATCH] Implements a system tray for dwm. + +Original author: Jan Christoph Ebersbach , inspired by http://code.google.com/p/dwm-plus +URL: http://dwm.suckless.org/patches/systray +dwm 6.2 port by Igor Gevka +--- + config.def.h | 4 + + dwm.c | 404 +++++++++++++++++++++++++++++++++++++++++++++++---- + 2 files changed, 382 insertions(+), 26 deletions(-) + +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 4465af1..3e361fa 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); +@@ -169,8 +193,10 @@ static void focus(Client *c); + static void focusin(XEvent *e); + static void focusmon(const Arg *arg); + static void focusstack(const Arg *arg); ++static Atom getatomprop(Client *c, Atom prop); + static int getrootptr(int *x, int *y); + static long getstate(Window w); ++static 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); +@@ -188,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); +@@ -206,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 *); +@@ -223,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; +@@ -257,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; +@@ -439,7 +475,7 @@ buttonpress(XEvent *e) + arg.ui = 1 << i; + } else if (ev->x < x + blw) + click = ClkLtSymbol; +- else if (ev->x > selmon->ww - TEXTW(stext)) ++ else if (ev->x > selmon->ww - TEXTW(stext) - getsystraywidth()) + click = ClkStatusText; + else + click = ClkWinTitle; +@@ -482,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++) +@@ -512,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]) { +@@ -567,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); +@@ -652,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 +@@ -695,19 +789,23 @@ dirtomon(int dir) + void + drawbar(Monitor *m) + { +- int x, w, sw = 0; ++ int x, w, sw = 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]); +- sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ +- drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0); ++ sw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ ++ drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0); + } + ++ resizebarwin(m); + for (c = m->clients; c; c = c->next) { + occ |= c->tags; + if (c->isurgent) +@@ -728,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 - sw - x) > bh) { ++ if ((w = m->ww - sw - 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); +@@ -739,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 +@@ -776,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 +@@ -862,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; +@@ -899,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) + { +@@ -1003,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); +@@ -1091,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; +@@ -1215,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) +@@ -1265,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) + { +@@ -1272,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) + { +@@ -1344,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) + { +@@ -1433,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; + } +@@ -1466,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 +@@ -1555,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); +@@ -1562,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); +@@ -1570,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(); +@@ -1701,7 +1889,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); + } + +@@ -1796,11 +1995,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, +@@ -1811,10 +2017,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); + } +@@ -1990,6 +2201,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 +@@ -2057,6 +2383,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) + { +@@ -2110,6 +2446,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) + { +-- +2.17.1 + diff --git a/stuff/manual-programs/suckless/dwm/dwm.1 b/stuff/manual-programs/suckless/dwm/dwm.1 new file mode 100644 index 0000000..13b3729 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/dwm.1 @@ -0,0 +1,176 @@ +.TH DWM 1 dwm\-VERSION +.SH NAME +dwm \- dynamic window manager +.SH SYNOPSIS +.B dwm +.RB [ \-v ] +.SH DESCRIPTION +dwm is a dynamic window manager for X. It manages windows in tiled, monocle +and floating layouts. Either layout can be applied dynamically, optimising the +environment for the application in use and the task performed. +.P +In tiled layouts windows are managed in a master and stacking area. The master +area on the left contains one window by default, and the stacking area on the +right contains all other windows. The number of master area windows can be +adjusted from zero to an arbitrary number. In monocle layout all windows are +maximised to the screen size. In floating layout windows can be resized and +moved freely. Dialog windows are always managed floating, regardless of the +layout applied. +.P +Windows are grouped by tags. Each window can be tagged with one or multiple +tags. Selecting certain tags displays all windows with these tags. +.P +Each screen contains a small status bar which displays all available tags, the +layout, the title of the focused window, and the text read from the root window +name property, if the screen is focused. A floating window is indicated with an +empty square and a maximised floating window is indicated with a filled square +before the windows title. The selected tags are indicated with a different +color. The tags of the focused window are indicated with a filled square in the +top left corner. The tags which are applied to one or more windows are +indicated with an empty square in the top left corner. +.P +dwm draws a small border around windows to indicate the focus state. +.SH OPTIONS +.TP +.B \-v +prints version information to standard output, then exits. +.SH USAGE +.SS Status bar +.TP +.B X root window name +is read and displayed in the status text area. It can be set with the +.BR xsetroot (1) +command. +.TP +.B Button1 +click on a tag label to display all windows with that tag, click on the layout +label toggles between tiled and floating layout. +.TP +.B Button3 +click on a tag label adds/removes all windows with that tag to/from the view. +.TP +.B Mod1\-Button1 +click on a tag label applies that tag to the focused window. +.TP +.B Mod1\-Button3 +click on a tag label adds/removes that tag to/from the focused window. +.SS Keyboard commands +.TP +.B Mod1\-Shift\-Return +Start +.BR st(1). +.TP +.B Mod1\-p +Spawn +.BR dmenu(1) +for launching other programs. +.TP +.B Mod1\-, +Focus previous screen, if any. +.TP +.B Mod1\-. +Focus next screen, if any. +.TP +.B Mod1\-Shift\-, +Send focused window to previous screen, if any. +.TP +.B Mod1\-Shift\-. +Send focused window to next screen, if any. +.TP +.B Mod1\-b +Toggles bar on and off. +.TP +.B Mod1\-t +Sets tiled layout. +.TP +.B Mod1\-f +Sets floating layout. +.TP +.B Mod1\-m +Sets monocle layout. +.TP +.B Mod1\-space +Toggles between current and previous layout. +.TP +.B Mod1\-j +Focus next window. +.TP +.B Mod1\-k +Focus previous window. +.TP +.B Mod1\-i +Increase number of windows in master area. +.TP +.B Mod1\-d +Decrease number of windows in master area. +.TP +.B Mod1\-l +Increase master area size. +.TP +.B Mod1\-h +Decrease master area size. +.TP +.B Mod1\-Return +Zooms/cycles focused window to/from master area (tiled layouts only). +.TP +.B Mod1\-Shift\-c +Close focused window. +.TP +.B Mod1\-Shift\-space +Toggle focused window between tiled and floating state. +.TP +.B Mod1\-Tab +Toggles to the previously selected tags. +.TP +.B Mod1\-Shift\-[1..n] +Apply nth tag to focused window. +.TP +.B Mod1\-Shift\-0 +Apply all tags to focused window. +.TP +.B Mod1\-Control\-Shift\-[1..n] +Add/remove nth tag to/from focused window. +.TP +.B Mod1\-[1..n] +View all windows with nth tag. +.TP +.B Mod1\-0 +View all windows with any tag. +.TP +.B Mod1\-Control\-[1..n] +Add/remove all windows with nth tag to/from the view. +.TP +.B Mod1\-Shift\-q +Quit dwm. +.SS Mouse commands +.TP +.B Mod1\-Button1 +Move focused window while dragging. Tiled windows will be toggled to the floating state. +.TP +.B Mod1\-Button2 +Toggles focused window between floating and tiled state. +.TP +.B Mod1\-Button3 +Resize focused window while dragging. Tiled windows will be toggled to the floating state. +.SH CUSTOMIZATION +dwm is customized by creating a custom config.h and (re)compiling the source +code. This keeps it fast, secure and simple. +.SH SEE ALSO +.BR dmenu (1), +.BR st (1) +.SH ISSUES +Java applications which use the XToolkit/XAWT backend may draw grey windows +only. The XToolkit/XAWT backend breaks ICCCM-compliance in recent JDK 1.5 and early +JDK 1.6 versions, because it assumes a reparenting window manager. Possible workarounds +are using JDK 1.4 (which doesn't contain the XToolkit/XAWT backend) or setting the +environment variable +.BR AWT_TOOLKIT=MToolkit +(to use the older Motif backend instead) or running +.B xprop -root -f _NET_WM_NAME 32a -set _NET_WM_NAME LG3D +or +.B wmname LG3D +(to pretend that a non-reparenting window manager is running that the +XToolkit/XAWT backend can recognize) or when using OpenJDK setting the environment variable +.BR _JAVA_AWT_WM_NONREPARENTING=1 . +.SH BUGS +Send all bug reports with a patch to hackers@suckless.org. diff --git a/stuff/manual-programs/suckless/dwm/dwm.c b/stuff/manual-programs/suckless/dwm/dwm.c new file mode 100644 index 0000000..8890d40 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/dwm.c @@ -0,0 +1,2588 @@ +/* See LICENSE file for copyright and license details. + * + * dynamic window manager is designed like any other X client as well. It is + * driven through handling X events. In contrast to other X clients, a window + * manager selects for SubstructureRedirectMask on the root window, to receive + * events about window (dis-)appearance. Only one X connection at a time is + * allowed to select for this event mask. + * + * The event handlers of dwm are organized in an array which is accessed + * whenever a new event has been fetched. This allows event dispatching + * in O(1) time. + * + * Each child of the root window is called a client, except windows which have + * set the override_redirect flag. Clients are organized in a linked client + * list on each monitor, the focus history is remembered through a stack list + * on each monitor. Each client contains a bit array to indicate the tags of a + * client. + * + * Keys and tagging rules are organized as arrays and defined in config.h. + * + * To understand everything else, start reading main(). + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef XINERAMA +#include +#endif /* XINERAMA */ +#include + +#include "drw.h" +#include "util.h" + +/* macros */ +#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) +#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) +#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ + * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) +#define 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 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 */ + +typedef union { + int i; + unsigned int ui; + float f; + const void *v; +} Arg; + +typedef struct { + unsigned int click; + unsigned int mask; + unsigned int button; + void (*func)(const Arg *arg); + const Arg arg; +} Button; + +typedef struct Monitor Monitor; +typedef struct Client Client; +struct Client { + char name[256]; + float mina, maxa; + int x, y, w, h; + int oldx, oldy, oldw, oldh; + int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int bw, oldbw; + unsigned int tags; + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; + Client *next; + Client *snext; + Monitor *mon; + Window win; +}; + +typedef struct { + unsigned int mod; + KeySym keysym; + void (*func)(const Arg *); + const Arg arg; +} Key; + +typedef struct { + const char *symbol; + void (*arrange)(Monitor *); +} Layout; + +struct Monitor { + char ltsymbol[16]; + float mfact; + int nmaster; + int num; + int by; /* bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ + int gappx; /* gaps between windows */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; + int showbar; + int topbar; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; + const Layout *lt[2]; +}; + +typedef struct { + const char *class; + const char *instance; + const char *title; + unsigned int tags; + int isfloating; + int monitor; +} Rule; + +typedef struct Systray Systray; +struct Systray { + Window win; + Client *icons; +}; + +/* function declarations */ +static void applyrules(Client *c); +static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); +static void arrange(Monitor *m); +static void arrangemon(Monitor *m); +static void attach(Client *c); +static void attachstack(Client *c); +static void buttonpress(XEvent *e); +static void checkotherwm(void); +static void cleanup(void); +static void cleanupmon(Monitor *mon); +static void clientmessage(XEvent *e); +static void configure(Client *c); +static void configurenotify(XEvent *e); +static void configurerequest(XEvent *e); +static Monitor *createmon(void); +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 enternotify(XEvent *e); +static void expose(XEvent *e); +static void focus(Client *c); +static void focusin(XEvent *e); +static void focusmon(const Arg *arg); +static void 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); +static void incnmaster(const Arg *arg); +static void keypress(XEvent *e); +static void killclient(const Arg *arg); +static void manage(Window w, XWindowAttributes *wa); +static void mappingnotify(XEvent *e); +static void maprequest(XEvent *e); +static void monocle(Monitor *m); +static void motionnotify(XEvent *e); +static void movemouse(const Arg *arg); +static Client *nexttiled(Client *c); +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 runAutostart(void); +static void scan(void); +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); +static void setfullscreen(Client *c, int fullscreen); +static void setgaps(const Arg *arg); +static void setlayout(const Arg *arg); +static void setmfact(const Arg *arg); +static void setup(void); +static void seturgent(Client *c, int urg); +static void 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 *); +static void togglebar(const Arg *arg); +static void togglefloating(const Arg *arg); +static void toggletag(const Arg *arg); +static void toggleview(const Arg *arg); +static void unfocus(Client *c, int setfocus); +static void unmanage(Client *c, int destroyed); +static void unmapnotify(XEvent *e); +static void updatebarpos(Monitor *m); +static void updatebars(void); +static void updateclientlist(void); +static 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); +static void bstack(Monitor *m); +static void bstackhoriz(Monitor *m); + +/* variables */ +static Systray *systray = NULL; +static const char broken[] = "broken"; +static char stext[256]; +static int screen; +static int sw, sh; /* X display screen geometry width, height */ +static int bh, blw = 0; /* bar geometry */ +static int lrpad; /* sum of left and right padding for text */ +static int (*xerrorxlib)(Display *, XErrorEvent *); +static unsigned int numlockmask = 0; +static void (*handler[LASTEvent]) (XEvent *) = { + [ButtonPress] = buttonpress, + [ClientMessage] = clientmessage, + [ConfigureRequest] = configurerequest, + [ConfigureNotify] = configurenotify, + [DestroyNotify] = destroynotify, + //[EnterNotify] = enternotify, + [Expose] = expose, + [FocusIn] = focusin, + [KeyPress] = keypress, + [MappingNotify] = mappingnotify, + [MapRequest] = maprequest, + [MotionNotify] = motionnotify, + [PropertyNotify] = propertynotify, + [ResizeRequest] = resizerequest, + [UnmapNotify] = unmapnotify +}; +static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; +static int running = 1; +static Cur *cursor[CurLast]; +static Clr **scheme; +static Display *dpy; +static Drw *drw; +static Monitor *mons, *selmon; +static Window root, wmcheckwin; + +/* configuration, allows nested code to access above variables */ +#include "config.h" + +/* compile-time check if all tags fit into an unsigned int bit array. */ +struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +/* function implementations */ +void +applyrules(Client *c) +{ + const char *class, *instance; + unsigned int i; + const Rule *r; + Monitor *m; + XClassHint ch = { NULL, NULL }; + + /* rule matching */ + c->isfloating = 0; + c->tags = 0; + XGetClassHint(dpy, c->win, &ch); + class = ch.res_class ? ch.res_class : broken; + instance = ch.res_name ? ch.res_name : broken; + + for (i = 0; i < LENGTH(rules); i++) { + r = &rules[i]; + if ((!r->title || strstr(c->name, r->title)) + && (!r->class || strstr(class, r->class)) + && (!r->instance || strstr(instance, r->instance))) + { + c->isfloating = r->isfloating; + c->tags |= r->tags; + for (m = mons; m && m->num != r->monitor; m = m->next); + if (m) + c->mon = m; + } + } + if (ch.res_class) + XFree(ch.res_class); + if (ch.res_name) + XFree(ch.res_name); + c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; +} + +int +applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) +{ + int baseismin; + Monitor *m = c->mon; + + /* set minimum possible */ + *w = MAX(1, *w); + *h = MAX(1, *h); + if (interact) { + if (*x > sw) + *x = sw - WIDTH(c); + if (*y > sh) + *y = sh - HEIGHT(c); + if (*x + *w + 2 * c->bw < 0) + *x = 0; + if (*y + *h + 2 * c->bw < 0) + *y = 0; + } else { + if (*x >= m->wx + m->ww) + *x = m->wx + m->ww - WIDTH(c); + if (*y >= m->wy + m->wh) + *y = m->wy + m->wh - HEIGHT(c); + if (*x + *w + 2 * c->bw <= m->wx) + *x = m->wx; + if (*y + *h + 2 * c->bw <= m->wy) + *y = m->wy; + } + if (*h < bh) + *h = bh; + if (*w < bh) + *w = bh; + if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { + /* see last two sentences in ICCCM 4.1.2.3 */ + baseismin = c->basew == c->minw && c->baseh == c->minh; + if (!baseismin) { /* temporarily remove base dimensions */ + *w -= c->basew; + *h -= c->baseh; + } + /* adjust for aspect limits */ + if (c->mina > 0 && c->maxa > 0) { + if (c->maxa < (float)*w / *h) + *w = *h * c->maxa + 0.5; + else if (c->mina < (float)*h / *w) + *h = *w * c->mina + 0.5; + } + if (baseismin) { /* increment calculation requires this */ + *w -= c->basew; + *h -= c->baseh; + } + /* adjust for increment value */ + if (c->incw) + *w -= *w % c->incw; + if (c->inch) + *h -= *h % c->inch; + /* restore base dimensions */ + *w = MAX(*w + c->basew, c->minw); + *h = MAX(*h + c->baseh, c->minh); + if (c->maxw) + *w = MIN(*w, c->maxw); + if (c->maxh) + *h = MIN(*h, c->maxh); + } + return *x != c->x || *y != c->y || *w != c->w || *h != c->h; +} + +void +arrange(Monitor *m) +{ + if (m) + showhide(m->stack); + else for (m = mons; m; m = m->next) + showhide(m->stack); + if (m) { + arrangemon(m); + restack(m); + } else for (m = mons; m; m = m->next) + arrangemon(m); +} + +void +arrangemon(Monitor *m) +{ + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); + if (m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); +} + +void +attach(Client *c) +{ + c->next = c->mon->clients; + c->mon->clients = c; +} + +void +attachstack(Client *c) +{ + c->snext = c->mon->stack; + c->mon->stack = c; +} + +void +buttonpress(XEvent *e) +{ + unsigned int i, x, click; + Arg arg = {0}; + Client *c; + Monitor *m; + XButtonPressedEvent *ev = &e->xbutton; + + click = ClkRootWin; + /* focus monitor if necessary */ + if ((m = wintomon(ev->window)) && m != selmon) { + unfocus(selmon->sel, 1); + selmon = m; + focus(NULL); + } + if (ev->window == selmon->barwin) { + i = x = 0; + 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 - TEXTW(stext) - getsystraywidth()) + click = ClkStatusText; + else + click = ClkWinTitle; + } else if ((c = wintoclient(ev->window))) { + focus(c); + restack(selmon); + XAllowEvents(dpy, ReplayPointer, CurrentTime); + click = ClkClientWin; + } + for (i = 0; i < LENGTH(buttons); i++) + if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button + && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) + buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); +} + +void +checkotherwm(void) +{ + xerrorxlib = XSetErrorHandler(xerrorstart); + /* this causes an error if some other window manager is running */ + XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask); + XSync(dpy, False); + XSetErrorHandler(xerror); + XSync(dpy, False); +} + +void +cleanup(void) +{ + Arg a = {.ui = ~0}; + Layout foo = { "", NULL }; + Monitor *m; + size_t i; + + view(&a); + selmon->lt[selmon->sellt] = &foo; + for (m = mons; m; m = m->next) + while (m->stack) + unmanage(m->stack, 0); + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); + if (showsystray) { + XUnmapWindow(dpy, systray->win); + XDestroyWindow(dpy, systray->win); + free(systray); + } + for (i = 0; i < CurLast; i++) + drw_cur_free(drw, cursor[i]); + for (i = 0; i < LENGTH(colors); i++) + free(scheme[i]); + XDestroyWindow(dpy, wmcheckwin); + drw_free(drw); + XSync(dpy, False); + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); +} + +void +cleanupmon(Monitor *mon) +{ + Monitor *m; + + if (mon == mons) + mons = mons->next; + else { + for (m = mons; m && m->next != mon; m = m->next); + m->next = mon->next; + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); + free(mon); +} + +void +clientmessage(XEvent *e) +{ + XWindowAttributes wa; + XSetWindowAttributes swa; + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); + + if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { + /* add systray icons */ + if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { + if (!(c = (Client *)calloc(1, sizeof(Client)))) + die("fatal: could not malloc() %u bytes\n", sizeof(Client)); + if (!(c->win = cme->data.l[2])) { + free(c); + return; + } + c->mon = selmon; + c->next = systray->icons; + systray->icons = c; + if (!XGetWindowAttributes(dpy, c->win, &wa)) { + /* use sane defaults */ + wa.width = bh; + wa.height = bh; + wa.border_width = 0; + } + c->x = c->oldx = c->y = c->oldy = 0; + c->w = c->oldw = wa.width; + c->h = c->oldh = wa.height; + c->oldbw = wa.border_width; + c->bw = 0; + c->isfloating = True; + /* reuse tags field as mapped status */ + c->tags = 1; + updatesizehints(c); + updatesystrayicongeom(c, wa.width, wa.height); + XAddToSaveSet(dpy, c->win); + XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); + 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); + /* 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]) { + if (cme->data.l[1] == netatom[NetWMFullscreen] + || cme->data.l[2] == netatom[NetWMFullscreen]) + setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */ + || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen))); + } else if (cme->message_type == netatom[NetActiveWindow]) { + if (c != selmon->sel && !c->isurgent) + seturgent(c, 1); + } +} + +void +configure(Client *c) +{ + XConfigureEvent ce; + + ce.type = ConfigureNotify; + ce.display = dpy; + ce.event = c->win; + ce.window = c->win; + ce.x = c->x; + ce.y = c->y; + ce.width = c->w; + ce.height = c->h; + ce.border_width = c->bw; + ce.above = None; + ce.override_redirect = False; + XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce); +} + +void +configurenotify(XEvent *e) +{ + Monitor *m; + Client *c; + XConfigureEvent *ev = &e->xconfigure; + int dirty; + + /* TODO: updategeom handling sucks, needs to be simplified */ + if (ev->window == root) { + dirty = (sw != ev->width || sh != ev->height); + sw = ev->width; + sh = ev->height; + if (updategeom() || dirty) { + drw_resize(drw, sw, bh); + updatebars(); + for (m = mons; m; m = m->next) { + for (c = m->clients; c; c = c->next) + if (c->isfullscreen) + resizeclient(c, m->mx, m->my, m->mw, m->mh); + resizebarwin(m); + } + focus(NULL); + arrange(NULL); + } + } +} + +void +configurerequest(XEvent *e) +{ + Client *c; + Monitor *m; + XConfigureRequestEvent *ev = &e->xconfigurerequest; + XWindowChanges wc; + + if ((c = wintoclient(ev->window))) { + if (ev->value_mask & CWBorderWidth) + c->bw = ev->border_width; + else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) { + m = c->mon; + if (ev->value_mask & CWX) { + c->oldx = c->x; + c->x = m->mx + ev->x; + } + if (ev->value_mask & CWY) { + c->oldy = c->y; + c->y = m->my + ev->y; + } + if (ev->value_mask & CWWidth) { + c->oldw = c->w; + c->w = ev->width; + } + if (ev->value_mask & CWHeight) { + c->oldh = c->h; + c->h = ev->height; + } + if ((c->x + c->w) > m->mx + m->mw && c->isfloating) + c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */ + if ((c->y + c->h) > m->my + m->mh && c->isfloating) + c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */ + if ((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight))) + configure(c); + if (ISVISIBLE(c)) + XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); + } else + configure(c); + } else { + wc.x = ev->x; + wc.y = ev->y; + wc.width = ev->width; + wc.height = ev->height; + wc.border_width = ev->border_width; + wc.sibling = ev->above; + wc.stack_mode = ev->detail; + XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); + } + XSync(dpy, False); +} + +Monitor * +createmon(void) +{ + Monitor *m; + + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; + m->mfact = mfact; + m->nmaster = nmaster; + m->showbar = showbar; + m->topbar = topbar; + m->gappx = gappx; + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); + return m; +} + +void +destroynotify(XEvent *e) +{ + Client *c; + XDestroyWindowEvent *ev = &e->xdestroywindow; + + if ((c = wintoclient(ev->window))) + unmanage(c, 1); + else if ((c = wintosystrayicon(ev->window))) { + removesystrayicon(c); + resizebarwin(selmon); + updatesystray(); + } +} + +void +detach(Client *c) +{ + Client **tc; + + for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next); + *tc = c->next; +} + +void +detachstack(Client *c) +{ + Client **tc, *t; + + for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext); + *tc = c->snext; + + if (c == c->mon->sel) { + for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext); + c->mon->sel = t; + } +} + +Monitor * +dirtomon(int dir) +{ + Monitor *m = NULL; + + if (dir > 0) { + if (!(m = selmon->next)) + m = mons; + } else if (selmon == mons) + for (m = mons; m->next; m = m->next); + else + for (m = mons; m->next != selmon; m = m->next); + return m; +} + +void +drawbar(Monitor *m) +{ + int x, w, sw = 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]); + sw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ + drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0); + } + + resizebarwin(m); + 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 ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); + if (occ & 1 << i) + drw_rect(drw, x + boxs, boxs, boxw, boxw, + m == selmon && selmon->sel && selmon->sel->tags & 1 << i, + urg & 1 << i); + x += w; + } + w = 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 - 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); + 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_map(drw, m->barwin, 0, 0, m->ww - stw, bh); +} + +void +drawbars(void) +{ + Monitor *m; + + for (m = mons; m; m = m->next) + drawbar(m); +} + +void +enternotify(XEvent *e) +{ + Client *c; + Monitor *m; + XCrossingEvent *ev = &e->xcrossing; + + if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root) + return; + c = wintoclient(ev->window); + m = c ? c->mon : wintomon(ev->window); + if (m != selmon) { + unfocus(selmon->sel, 1); + selmon = m; + } else if (!c || c == selmon->sel) + return; + focus(c); +} + +void +expose(XEvent *e) +{ + Monitor *m; + XExposeEvent *ev = &e->xexpose; + + if (ev->count == 0 && (m = wintomon(ev->window))) { + drawbar(m); + if (m == selmon) + updatesystray(); + } +} + +void +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); + if (c) { + if (c->mon != selmon) + selmon = c->mon; + if (c->isurgent) + seturgent(c, 0); + detachstack(c); + attachstack(c); + grabbuttons(c, 1); + XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); + setfocus(c); + } else { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); + } + selmon->sel = c; + drawbars(); +} + +/* there are some broken focus acquiring clients needing extra handling */ +void +focusin(XEvent *e) +{ + XFocusChangeEvent *ev = &e->xfocus; + + if (selmon->sel && ev->window != selmon->sel->win) + setfocus(selmon->sel); +} + +void +focusmon(const Arg *arg) +{ + Monitor *m; + + if (!mons->next) + return; + if ((m = dirtomon(arg->i)) == selmon) + return; + unfocus(selmon->sel, 0); + selmon = m; + focus(NULL); +} + +void +focusstack(const Arg *arg) +{ + Client *c = NULL, *i; + + if (!selmon->sel) + return; + if (arg->i > 0) { + for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); + if (!c) + for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); + } else { + for (i = selmon->clients; i != selmon->sel; i = i->next) + if (ISVISIBLE(i)) + c = i; + if (!c) + for (; i; i = i->next) + if (ISVISIBLE(i)) + c = i; + } + if (c) { + focus(c); + restack(selmon); + } +} + +Atom +getatomprop(Client *c, Atom prop) +{ + int di; + 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, 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; +} + +int +getrootptr(int *x, int *y) +{ + int di; + unsigned int dui; + Window dummy; + + return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui); +} + +long +getstate(Window w) +{ + int format; + long result = -1; + unsigned char *p = NULL; + unsigned long n, extra; + Atom real; + + if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState], + &real, &format, &n, &extra, (unsigned char **)&p) != Success) + return -1; + if (n != 0) + result = *p; + XFree(p); + return result; +} + +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) +{ + char **list = NULL; + int n; + XTextProperty name; + + if (!text || size == 0) + return 0; + text[0] = '\0'; + if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems) + return 0; + if (name.encoding == XA_STRING) + strncpy(text, (char *)name.value, size - 1); + else { + if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) { + strncpy(text, *list, size - 1); + XFreeStringList(list); + } + } + text[size - 1] = '\0'; + XFree(name.value); + return 1; +} + +void +grabbuttons(Client *c, int focused) +{ + updatenumlockmask(); + { + unsigned int i, j; + unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); + if (!focused) + XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, + BUTTONMASK, GrabModeSync, GrabModeSync, None, None); + for (i = 0; i < LENGTH(buttons); i++) + if (buttons[i].click == ClkClientWin) + for (j = 0; j < LENGTH(modifiers); j++) + XGrabButton(dpy, buttons[i].button, + buttons[i].mask | modifiers[j], + c->win, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, None); + } +} + +void +grabkeys(void) +{ + updatenumlockmask(); + { + unsigned int i, j; + unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; + KeyCode code; + + XUngrabKey(dpy, AnyKey, AnyModifier, root); + for (i = 0; i < LENGTH(keys); i++) + if ((code = XKeysymToKeycode(dpy, keys[i].keysym))) + for (j = 0; j < LENGTH(modifiers); j++) + XGrabKey(dpy, code, keys[i].mod | modifiers[j], root, + True, GrabModeAsync, GrabModeAsync); + } +} + +void +incnmaster(const Arg *arg) +{ + selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); +} + +#ifdef XINERAMA +static int +isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) +{ + while (n--) + if (unique[n].x_org == info->x_org && unique[n].y_org == info->y_org + && unique[n].width == info->width && unique[n].height == info->height) + return 0; + return 1; +} +#endif /* XINERAMA */ + +void +keypress(XEvent *e) +{ + unsigned int i; + KeySym keysym; + XKeyEvent *ev; + + ev = &e->xkey; + keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); + for (i = 0; i < LENGTH(keys); i++) + if (keysym == keys[i].keysym + && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) + && keys[i].func) + keys[i].func(&(keys[i].arg)); +} + +void +killclient(const Arg *arg) +{ + if (!selmon->sel) + return; + if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { + XGrabServer(dpy); + XSetErrorHandler(xerrordummy); + XSetCloseDownMode(dpy, DestroyAll); + XKillClient(dpy, selmon->sel->win); + XSync(dpy, False); + XSetErrorHandler(xerror); + XUngrabServer(dpy); + } +} + +void +manage(Window w, XWindowAttributes *wa) +{ + Client *c, *t = NULL; + Window trans = None; + XWindowChanges wc; + + c = ecalloc(1, sizeof(Client)); + c->win = w; + /* geometry */ + c->x = c->oldx = wa->x; + c->y = c->oldy = wa->y; + c->w = c->oldw = wa->width; + c->h = c->oldh = wa->height; + c->oldbw = wa->border_width; + + updatetitle(c); + if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { + c->mon = t->mon; + c->tags = t->tags; + } else { + c->mon = selmon; + applyrules(c); + } + + if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw) + c->x = c->mon->mx + c->mon->mw - WIDTH(c); + if (c->y + HEIGHT(c) > c->mon->my + c->mon->mh) + 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->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); + configure(c); /* propagates border_width, if size doesn't change */ + updatewindowtype(c); + updatesizehints(c); + updatewmhints(c); + XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); + grabbuttons(c, 0); + if (!c->isfloating) + c->isfloating = c->oldstate = trans != None || c->isfixed; + if (c->isfloating) + XRaiseWindow(dpy, c->win); + attach(c); + attachstack(c); + XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); + XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ + setclientstate(c, NormalState); + if (c->mon == selmon) + unfocus(selmon->sel, 0); + c->mon->sel = c; + arrange(c->mon); + XMapWindow(dpy, c->win); + focus(NULL); +} + +void +mappingnotify(XEvent *e) +{ + XMappingEvent *ev = &e->xmapping; + + XRefreshKeyboardMapping(ev); + if (ev->request == MappingKeyboard) + grabkeys(); +} + +void +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; + if (wa.override_redirect) + return; + 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); +} + +void +motionnotify(XEvent *e) +{ + static Monitor *mon = NULL; + Monitor *m; + XMotionEvent *ev = &e->xmotion; + + if (ev->window != root) + return; + if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { + unfocus(selmon->sel, 1); + selmon = m; + focus(NULL); + } + mon = m; +} + +void +movemouse(const Arg *arg) +{ + int x, y, ocx, ocy, nx, ny; + Client *c; + Monitor *m; + XEvent ev; + Time lasttime = 0; + + if (!(c = selmon->sel)) + return; + if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ + return; + restack(selmon); + ocx = c->x; + ocy = c->y; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, + None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) + return; + if (!getrootptr(&x, &y)) + return; + do { + XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); + switch(ev.type) { + case ConfigureRequest: + case Expose: + case MapRequest: + handler[ev.type](&ev); + break; + case MotionNotify: + if ((ev.xmotion.time - lasttime) <= (1000 / 60)) + continue; + lasttime = ev.xmotion.time; + + nx = ocx + (ev.xmotion.x - x); + ny = ocy + (ev.xmotion.y - y); + if (abs(selmon->wx - nx) < snap) + nx = selmon->wx; + else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) + nx = selmon->wx + selmon->ww - WIDTH(c); + if (abs(selmon->wy - ny) < snap) + ny = selmon->wy; + else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap) + ny = selmon->wy + selmon->wh - HEIGHT(c); + if (!c->isfloating && selmon->lt[selmon->sellt]->arrange + && (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) + togglefloating(NULL); + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) + resize(c, nx, ny, c->w, c->h, 1); + break; + } + } while (ev.type != ButtonRelease); + XUngrabPointer(dpy, CurrentTime); + if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { + sendmon(c, m); + selmon = m; + focus(NULL); + } +} + +Client * +nexttiled(Client *c) +{ + for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); + return c; +} + +void +pop(Client *c) +{ + detach(c); + attach(c); + focus(c); + arrange(c->mon); +} + +void +propertynotify(XEvent *e) +{ + Client *c; + 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) + return; /* ignore */ + else if ((c = wintoclient(ev->window))) { + switch(ev->atom) { + default: break; + case XA_WM_TRANSIENT_FOR: + if (!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) && + (c->isfloating = (wintoclient(trans)) != NULL)) + arrange(c->mon); + break; + case XA_WM_NORMAL_HINTS: + updatesizehints(c); + break; + case XA_WM_HINTS: + updatewmhints(c); + drawbars(); + break; + } + if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { + updatetitle(c); + if (c == c->mon->sel) + drawbar(c->mon); + } + if (ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); + } +} + +void +quit(const Arg *arg) +{ + running = 0; +} + +Monitor * +recttomon(int x, int y, int w, int h) +{ + Monitor *m, *r = selmon; + int a, area = 0; + + for (m = mons; m; m = m->next) + if ((a = INTERSECT(x, y, w, h, m)) > area) { + area = a; + r = m; + } + return r; +} + +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) +{ + if (applysizehints(c, &x, &y, &w, &h, 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) +{ + XWindowChanges wc; + + c->oldx = c->x; c->x = wc.x = x; + c->oldy = c->y; c->y = wc.y = y; + c->oldw = c->w; c->w = wc.width = w; + c->oldh = c->h; c->h = wc.height = h; + wc.border_width = c->bw; + XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); + configure(c); + XSync(dpy, False); +} + +void +resizemouse(const Arg *arg) +{ + int ocx, ocy, nw, nh; + Client *c; + Monitor *m; + XEvent ev; + Time lasttime = 0; + + if (!(c = selmon->sel)) + return; + if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ + return; + restack(selmon); + ocx = c->x; + ocy = c->y; + 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); + 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; + + nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); + nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); + if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww + && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh) + { + if (!c->isfloating && selmon->lt[selmon->sellt]->arrange + && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) + togglefloating(NULL); + } + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) + resize(c, c->x, c->y, nw, nh, 1); + break; + } + } while (ev.type != ButtonRelease); + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); + XUngrabPointer(dpy, CurrentTime); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); + if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { + sendmon(c, m); + selmon = m; + focus(NULL); + } +} + +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) +{ + Client *c; + XEvent ev; + XWindowChanges wc; + + drawbar(m); + if (!m->sel) + return; + if (m->sel->isfloating || !m->lt[m->sellt]->arrange) + XRaiseWindow(dpy, m->sel->win); + if (m->lt[m->sellt]->arrange) { + wc.stack_mode = Below; + wc.sibling = m->barwin; + for (c = m->stack; c; c = c->snext) + if (!c->isfloating && ISVISIBLE(c)) { + XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc); + wc.sibling = c->win; + } + } + XSync(dpy, False); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); +} + +void +run(void) +{ + XEvent ev; + /* main event loop */ + XSync(dpy, False); + while (running && !XNextEvent(dpy, &ev)) + if (handler[ev.type]) + handler[ev.type](&ev); /* call handler */ +} + +void +runAutostart(void) { + system("cd ~/.config/dwm; ./autostart_blocking.sh"); + system("cd ~/.config/dwm; ./autostart.sh &"); +} + +void +scan(void) +{ + unsigned int i, num; + Window d1, d2, *wins = NULL; + XWindowAttributes wa; + + if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { + for (i = 0; i < num; i++) { + if (!XGetWindowAttributes(dpy, wins[i], &wa) + || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) + continue; + if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) + manage(wins[i], &wa); + } + for (i = 0; i < num; i++) { /* now the transients */ + if (!XGetWindowAttributes(dpy, wins[i], &wa)) + continue; + if (XGetTransientForHint(dpy, wins[i], &d1) + && (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)) + manage(wins[i], &wa); + } + if (wins) + XFree(wins); + } +} + +void +sendmon(Client *c, Monitor *m) +{ + if (c->mon == m) + return; + unfocus(c, 1); + detach(c); + detachstack(c); + c->mon = m; + c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ + attach(c); + attachstack(c); + focus(NULL); + arrange(NULL); +} + +void +setclientstate(Client *c, long state) +{ + long data[] = { state, None }; + + XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, + PropModeReplace, (unsigned char *)data, 2); +} + +int +sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) +{ + int n; + Atom *protocols, mt; + int exists = 0; + XEvent ev; + + 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 = 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); + } + return exists; +} + +void +setfocus(Client *c) +{ + if (!c->neverfocus) { + XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); + XChangeProperty(dpy, root, netatom[NetActiveWindow], + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(c->win), 1); + } + sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); +} + +void +setfullscreen(Client *c, int fullscreen) +{ + if (fullscreen && !c->isfullscreen) { + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, + PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); + c->isfullscreen = 1; + c->oldstate = c->isfloating; + c->oldbw = c->bw; + c->bw = 0; + c->isfloating = 1; + resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); + XRaiseWindow(dpy, c->win); + } else if (!fullscreen && c->isfullscreen){ + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, + PropModeReplace, (unsigned char*)0, 0); + c->isfullscreen = 0; + c->isfloating = c->oldstate; + c->bw = c->oldbw; + c->x = c->oldx; + c->y = c->oldy; + c->w = c->oldw; + c->h = c->oldh; + resizeclient(c, c->x, c->y, c->w, c->h); + arrange(c->mon); + } +} + +void +setgaps(const Arg *arg) +{ + if ((arg->i == 0) || (selmon->gappx + arg->i < 0)) + selmon->gappx = 0; + else + selmon->gappx += arg->i; + arrange(selmon); +} + +void +setlayout(const Arg *arg) +{ + if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) + selmon->sellt ^= 1; + if (arg && arg->v) + selmon->lt[selmon->sellt] = (Layout *)arg->v; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if (selmon->sel) + arrange(selmon); + else + drawbar(selmon); +} + +/* arg > 1.0 will set mfact absolutely */ +void +setmfact(const Arg *arg) +{ + float f; + + if (!arg || !selmon->lt[selmon->sellt]->arrange) + return; + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if (f < 0.1 || f > 0.9) + return; + selmon->mfact = f; + arrange(selmon); +} + +void +setup(void) +{ + int i; + XSetWindowAttributes wa; + Atom utf8string; + + /* clean up any zombies immediately */ + sigchld(0); + + /* init screen */ + screen = DefaultScreen(dpy); + sw = DisplayWidth(dpy, screen); + sh = DisplayHeight(dpy, screen); + root = RootWindow(dpy, screen); + 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; + updategeom(); + /* init atoms */ + utf8string = XInternAtom(dpy, "UTF8_STRING", False); + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); + wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); + wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); + netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); + netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); + netatom[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); + 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); + 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); + cursor[CurMove] = drw_cur_create(drw, XC_fleur); + /* init appearance */ + scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); + for (i = 0; i < LENGTH(colors); i++) + scheme[i] = drw_scm_create(drw, colors[i], 3); + /* init system tray */ + updatesystray(); + /* init bars */ + updatebars(); + updatestatus(); + /* supporting window for NetWMCheck */ + wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0); + XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32, + PropModeReplace, (unsigned char *) &wmcheckwin, 1); + XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8, + PropModeReplace, (unsigned char *) "dwm", 3); + XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32, + PropModeReplace, (unsigned char *) &wmcheckwin, 1); + /* EWMH support per view */ + XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, + PropModeReplace, (unsigned char *) netatom, NetLast); + XDeleteProperty(dpy, root, netatom[NetClientList]); + /* select events */ + wa.cursor = cursor[CurNormal]->cursor; + wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask + |ButtonPressMask|PointerMotionMask|EnterWindowMask + |LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; + XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); + XSelectInput(dpy, root, wa.event_mask); + grabkeys(); + focus(NULL); +} + + +void +seturgent(Client *c, int urg) +{ + XWMHints *wmh; + + c->isurgent = urg; + if (!(wmh = XGetWMHints(dpy, c->win))) + return; + wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint); + XSetWMHints(dpy, c->win, wmh); + XFree(wmh); +} + +void +showhide(Client *c) +{ + if (!c) + return; + if (ISVISIBLE(c)) { + /* show clients top down */ + XMoveWindow(dpy, c->win, c->x, c->y); + if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen) + resize(c, c->x, c->y, c->w, c->h, 0); + showhide(c->snext); + } else { + /* hide clients bottom up */ + showhide(c->snext); + XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y); + } +} + +void +sigchld(int unused) +{ + if (signal(SIGCHLD, sigchld) == SIG_ERR) + die("can't install SIGCHLD handler:"); + while (0 < waitpid(-1, NULL, WNOHANG)); +} + +void +spawn(const Arg *arg) +{ + if (arg->v == dmenucmd) + dmenumon[0] = '0' + selmon->num; + if (fork() == 0) { + if (dpy) + close(ConnectionNumber(dpy)); + setsid(); + execvp(((char **)arg->v)[0], (char **)arg->v); + fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]); + perror(" failed"); + exit(EXIT_SUCCESS); + } +} + +void +tag(const Arg *arg) +{ + if (selmon->sel && arg->ui & TAGMASK) { + selmon->sel->tags = arg->ui & TAGMASK; + focus(NULL); + arrange(selmon); + } +} + +void +tagmon(const Arg *arg) +{ + if (!selmon->sel || !mons->next) + return; + sendmon(selmon->sel, dirtomon(arg->i)); +} + +void +tile(Monitor *m) +{ + unsigned int i, n, h, mw, my, ty; + Client *c; + + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if (n == 0) + return; + + if (n > m->nmaster) + mw = m->nmaster ? m->ww * m->mfact : 0; + else + mw = m->ww - m->gappx; + for (i = 0, my = ty = m->gappx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { + h = (m->wh - my) / (MIN(n, m->nmaster) - i) - m->gappx; + resize(c, m->wx + m->gappx, m->wy + my, mw - (2*c->bw) - m->gappx, h - (2*c->bw), 0); + my += HEIGHT(c) + m->gappx; + } else { + h = (m->wh - ty) / (n - i) - m->gappx; + resize(c, m->wx + mw + m->gappx, m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->gappx, h - (2*c->bw), 0); + ty += HEIGHT(c) + m->gappx; + } +} + +void +togglebar(const Arg *arg) +{ + selmon->showbar = !selmon->showbar; + updatebarpos(selmon); + 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); +} + +void +togglefloating(const Arg *arg) +{ + if (!selmon->sel) + return; + if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ + return; + selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed; + if (selmon->sel->isfloating) + resize(selmon->sel, selmon->sel->x, selmon->sel->y, + selmon->sel->w, selmon->sel->h, 0); + arrange(selmon); +} + +void +toggletag(const Arg *arg) +{ + unsigned int newtags; + + if (!selmon->sel) + return; + newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); + if (newtags) { + selmon->sel->tags = newtags; + focus(NULL); + arrange(selmon); + } +} + +void +toggleview(const Arg *arg) +{ + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + + if (newtagset) { + selmon->tagset[selmon->seltags] = newtagset; + focus(NULL); + arrange(selmon); + } +} + +void +unfocus(Client *c, int setfocus) +{ + if (!c) + return; + grabbuttons(c, 0); + XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); + if (setfocus) { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); + } +} + +void +unmanage(Client *c, int destroyed) +{ + Monitor *m = c->mon; + XWindowChanges wc; + + detach(c); + detachstack(c); + if (!destroyed) { + wc.border_width = c->oldbw; + XGrabServer(dpy); /* avoid race conditions */ + XSetErrorHandler(xerrordummy); + XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */ + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); + setclientstate(c, WithdrawnState); + XSync(dpy, False); + XSetErrorHandler(xerror); + XUngrabServer(dpy); + } + free(c); + focus(NULL); + updateclientlist(); + arrange(m); +} + +void +unmapnotify(XEvent *e) +{ + Client *c; + XUnmapEvent *ev = &e->xunmap; + + if ((c = wintoclient(ev->window))) { + if (ev->send_event) + setclientstate(c, WithdrawnState); + 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, + .background_pixmap = ParentRelative, + .event_mask = ButtonPressMask|ExposureMask + }; + XClassHint ch = {"dwm", "dwm"}; + for (m = mons; m; m = m->next) { + if (m->barwin) + continue; + 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); + } +} + +void +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; + } else + m->by = -bh; +} + +void +updateclientlist() +{ + Client *c; + Monitor *m; + + XDeleteProperty(dpy, root, netatom[NetClientList]); + for (m = mons; m; m = m->next) + for (c = m->clients; c; c = c->next) + XChangeProperty(dpy, root, netatom[NetClientList], + XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); +} + +int +updategeom(void) +{ + int dirty = 0; + +#ifdef XINERAMA + if (XineramaIsActive(dpy)) { + int i, j, n, nn; + Client *c; + Monitor *m; + XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn); + XineramaScreenInfo *unique = NULL; + + for (n = 0, m = mons; m; m = m->next, n++); + /* only consider unique geometries as separate screens */ + unique = ecalloc(nn, sizeof(XineramaScreenInfo)); + for (i = 0, j = 0; i < nn; i++) + if (isuniquegeom(unique, j, &info[i])) + memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo)); + XFree(info); + nn = j; + if (n <= nn) { /* new monitors available */ + for (i = 0; i < (nn - n); i++) { + for (m = mons; m && m->next; m = m->next); + if (m) + m->next = createmon(); + else + mons = createmon(); + } + for (i = 0, m = mons; i < nn && m; m = m->next, i++) + if (i >= n + || unique[i].x_org != m->mx || unique[i].y_org != m->my + || unique[i].width != m->mw || unique[i].height != m->mh) + { + dirty = 1; + m->num = i; + m->mx = m->wx = unique[i].x_org; + m->my = m->wy = unique[i].y_org; + m->mw = m->ww = unique[i].width; + m->mh = m->wh = unique[i].height; + updatebarpos(m); + } + } else { /* less monitors available nn < n */ + for (i = nn; i < n; i++) { + for (m = mons; m && m->next; m = m->next); + while ((c = m->clients)) { + dirty = 1; + m->clients = c->next; + detachstack(c); + c->mon = mons; + attach(c); + attachstack(c); + } + if (m == selmon) + selmon = mons; + cleanupmon(m); + } + } + free(unique); + } else +#endif /* XINERAMA */ + { /* default monitor setup */ + if (!mons) + mons = createmon(); + if (mons->mw != sw || mons->mh != sh) { + dirty = 1; + mons->mw = mons->ww = sw; + mons->mh = mons->wh = sh; + updatebarpos(mons); + } + } + if (dirty) { + selmon = mons; + selmon = wintomon(root); + } + return dirty; +} + +void +updatenumlockmask(void) +{ + unsigned int i, j; + XModifierKeymap *modmap; + + numlockmask = 0; + modmap = XGetModifierMapping(dpy); + for (i = 0; i < 8; i++) + for (j = 0; j < modmap->max_keypermod; j++) + if (modmap->modifiermap[i * modmap->max_keypermod + j] + == XKeysymToKeycode(dpy, XK_Num_Lock)) + numlockmask = (1 << i); + XFreeModifiermap(modmap); +} + +void +updatesizehints(Client *c) +{ + long msize; + XSizeHints size; + + if (!XGetWMNormalHints(dpy, c->win, &size, &msize)) + /* size is uninitialized, ensure that size.flags aren't used */ + size.flags = PSize; + if (size.flags & PBaseSize) { + c->basew = size.base_width; + c->baseh = size.base_height; + } else if (size.flags & PMinSize) { + c->basew = size.min_width; + c->baseh = size.min_height; + } else + c->basew = c->baseh = 0; + if (size.flags & PResizeInc) { + c->incw = size.width_inc; + c->inch = size.height_inc; + } else + c->incw = c->inch = 0; + if (size.flags & PMaxSize) { + c->maxw = size.max_width; + c->maxh = size.max_height; + } else + c->maxw = c->maxh = 0; + if (size.flags & PMinSize) { + c->minw = size.min_width; + c->minh = size.min_height; + } else if (size.flags & PBaseSize) { + c->minw = size.base_width; + c->minh = size.base_height; + } else + c->minw = c->minh = 0; + if (size.flags & PAspect) { + c->mina = (float)size.min_aspect.y / size.min_aspect.x; + c->maxa = (float)size.max_aspect.x / size.max_aspect.y; + } else + c->maxa = c->mina = 0.0; + c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh); +} + +void +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 +updatetitle(Client *c) +{ + if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name)) + gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name); + if (c->name[0] == '\0') /* hack to mark broken clients */ + strcpy(c->name, broken); +} + +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; +} + +void +updatewmhints(Client *c) +{ + XWMHints *wmh; + + if ((wmh = XGetWMHints(dpy, c->win))) { + if (c == selmon->sel && wmh->flags & XUrgencyHint) { + wmh->flags &= ~XUrgencyHint; + XSetWMHints(dpy, c->win, wmh); + } else + c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0; + if (wmh->flags & InputHint) + c->neverfocus = !wmh->input; + else + c->neverfocus = 0; + XFree(wmh); + } +} + +void +view(const Arg *arg) +{ + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ + if (arg->ui & TAGMASK) + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + focus(NULL); + arrange(selmon); +} + +Client * +wintoclient(Window w) +{ + Client *c; + Monitor *m; + + for (m = mons; m; m = m->next) + for (c = m->clients; c; c = c->next) + if (c->win == w) + return c; + return NULL; +} + +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) +{ + int x, y; + Client *c; + Monitor *m; + + if (w == root && getrootptr(&x, &y)) + return recttomon(x, y, 1, 1); + for (m = mons; m; m = m->next) + if (w == m->barwin) + return m; + if ((c = wintoclient(w))) + return c->mon; + return selmon; +} + +/* 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. */ +int +xerror(Display *dpy, XErrorEvent *ee) +{ + if (ee->error_code == BadWindow + || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch) + || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable) + || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable) + || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable) + || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch) + || (ee->request_code == X_GrabButton && ee->error_code == BadAccess) + || (ee->request_code == X_GrabKey && ee->error_code == BadAccess) + || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable)) + return 0; + fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n", + ee->request_code, ee->error_code); + return xerrorxlib(dpy, ee); /* may call exit */ +} + +int +xerrordummy(Display *dpy, XErrorEvent *ee) +{ + return 0; +} + +/* Startup Error handler to check if another window manager + * is already running. */ +int +xerrorstart(Display *dpy, XErrorEvent *ee) +{ + die("dwm: another window manager is already running"); + return -1; +} + +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) +{ + Client *c = selmon->sel; + + if (!selmon->lt[selmon->sellt]->arrange + || (selmon->sel && selmon->sel->isfloating)) + return; + if (c == nexttiled(selmon->clients)) + if (!c || !(c = nexttiled(c->next))) + return; + pop(c); +} + +int +main(int argc, char *argv[]) +{ + if (argc == 2 && !strcmp("-v", argv[1])) + die("dwm-"VERSION); + else if (argc != 1) + die("usage: dwm [-v]"); + if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) + fputs("warning: no locale support\n", stderr); + if (!(dpy = XOpenDisplay(NULL))) + die("dwm: cannot open display"); + checkotherwm(); + setup(); +#ifdef __OpenBSD__ + if (pledge("stdio rpath proc exec", NULL) == -1) + die("pledge"); +#endif /* __OpenBSD__ */ + scan(); + runAutostart(); + run(); + cleanup(); + XCloseDisplay(dpy); + return EXIT_SUCCESS; +} + +static void +bstack(Monitor *m) { + int w, h, mh, mx, tx, ty, tw; + unsigned int i, n; + Client *c; + + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if (n == 0) + return; + if (n > m->nmaster) { + mh = m->nmaster ? m->mfact * m->wh : 0; + tw = m->ww / (n - m->nmaster); + ty = m->wy + mh; + } else { + mh = m->wh; + tw = m->ww; + ty = m->wy; + } + for (i = mx = 0, tx = m->wx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { + if (i < m->nmaster) { + w = (m->ww - mx) / (MIN(n, m->nmaster) - i); + resize(c, m->wx + mx, m->wy, w - (2 * c->bw), mh - (2 * c->bw), 0); + mx += WIDTH(c); + } else { + h = m->wh - mh; + resize(c, tx, ty, tw - (2 * c->bw), h - (2 * c->bw), 0); + if (tw != m->ww) + tx += WIDTH(c); + } + } +} + +static void +bstackhoriz(Monitor *m) { + int w, mh, mx, tx, ty, th; + unsigned int i, n; + Client *c; + + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if (n == 0) + return; + if (n > m->nmaster) { + mh = m->nmaster ? m->mfact * m->wh : 0; + th = (m->wh - mh) / (n - m->nmaster); + ty = m->wy + mh; + } else { + th = mh = m->wh; + ty = m->wy; + } + for (i = mx = 0, tx = m->wx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { + if (i < m->nmaster) { + w = (m->ww - mx) / (MIN(n, m->nmaster) - i); + resize(c, m->wx + mx, m->wy, w - (2 * c->bw), mh - (2 * c->bw), 0); + mx += WIDTH(c); + } else { + resize(c, tx, ty, m->ww - (2 * c->bw), th - (2 * c->bw), 0); + if (th != m->wh) + ty += HEIGHT(c); + } + } +} diff --git a/stuff/manual-programs/suckless/dwm/dwm.c.orig b/stuff/manual-programs/suckless/dwm/dwm.c.orig new file mode 100644 index 0000000..0f0365a --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/dwm.c.orig @@ -0,0 +1,2516 @@ +/* See LICENSE file for copyright and license details. + * + * dynamic window manager is designed like any other X client as well. It is + * driven through handling X events. In contrast to other X clients, a window + * manager selects for SubstructureRedirectMask on the root window, to receive + * events about window (dis-)appearance. Only one X connection at a time is + * allowed to select for this event mask. + * + * The event handlers of dwm are organized in an array which is accessed + * whenever a new event has been fetched. This allows event dispatching + * in O(1) time. + * + * Each child of the root window is called a client, except windows which have + * set the override_redirect flag. Clients are organized in a linked client + * list on each monitor, the focus history is remembered through a stack list + * on each monitor. Each client contains a bit array to indicate the tags of a + * client. + * + * Keys and tagging rules are organized as arrays and defined in config.h. + * + * To understand everything else, start reading main(). + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef XINERAMA +#include +#endif /* XINERAMA */ +#include + +#include "drw.h" +#include "util.h" + +/* macros */ +#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) +#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) +#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ + * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) +#define 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 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 */ + +typedef union { + int i; + unsigned int ui; + float f; + const void *v; +} Arg; + +typedef struct { + unsigned int click; + unsigned int mask; + unsigned int button; + void (*func)(const Arg *arg); + const Arg arg; +} Button; + +typedef struct Monitor Monitor; +typedef struct Client Client; +struct Client { + char name[256]; + float mina, maxa; + int x, y, w, h; + int oldx, oldy, oldw, oldh; + int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int bw, oldbw; + unsigned int tags; + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; + Client *next; + Client *snext; + Monitor *mon; + Window win; +}; + +typedef struct { + unsigned int mod; + KeySym keysym; + void (*func)(const Arg *); + const Arg arg; +} Key; + +typedef struct { + const char *symbol; + void (*arrange)(Monitor *); +} Layout; + +struct Monitor { + char ltsymbol[16]; + float mfact; + int nmaster; + int num; + int by; /* bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ + int gappx; /* gaps between windows */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; + int showbar; + int topbar; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; + const Layout *lt[2]; +}; + +typedef struct { + const char *class; + const char *instance; + const char *title; + unsigned int tags; + int isfloating; + int monitor; +} Rule; + +typedef struct Systray Systray; +struct Systray { + Window win; + Client *icons; +}; + +/* function declarations */ +static void applyrules(Client *c); +static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); +static void arrange(Monitor *m); +static void arrangemon(Monitor *m); +static void attach(Client *c); +static void attachstack(Client *c); +static void buttonpress(XEvent *e); +static void checkotherwm(void); +static void cleanup(void); +static void cleanupmon(Monitor *mon); +static void clientmessage(XEvent *e); +static void configure(Client *c); +static void configurenotify(XEvent *e); +static void configurerequest(XEvent *e); +static Monitor *createmon(void); +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 enternotify(XEvent *e); +static void expose(XEvent *e); +static void focus(Client *c); +static void focusin(XEvent *e); +static void focusmon(const Arg *arg); +static void 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); +static void incnmaster(const Arg *arg); +static void keypress(XEvent *e); +static void killclient(const Arg *arg); +static void manage(Window w, XWindowAttributes *wa); +static void mappingnotify(XEvent *e); +static void maprequest(XEvent *e); +static void monocle(Monitor *m); +static void motionnotify(XEvent *e); +static void movemouse(const Arg *arg); +static Client *nexttiled(Client *c); +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(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); +static void setfullscreen(Client *c, int fullscreen); +static void setgaps(const Arg *arg); +static void setlayout(const Arg *arg); +static void setmfact(const Arg *arg); +static void setup(void); +static void seturgent(Client *c, int urg); +static void 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 *); +static void togglebar(const Arg *arg); +static void togglefloating(const Arg *arg); +static void toggletag(const Arg *arg); +static void toggleview(const Arg *arg); +static void unfocus(Client *c, int setfocus); +static void unmanage(Client *c, int destroyed); +static void unmapnotify(XEvent *e); +static void updatebarpos(Monitor *m); +static void updatebars(void); +static void updateclientlist(void); +static 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; +static int sw, sh; /* X display screen geometry width, height */ +static int bh, blw = 0; /* bar geometry */ +static int lrpad; /* sum of left and right padding for text */ +static int (*xerrorxlib)(Display *, XErrorEvent *); +static unsigned int numlockmask = 0; +static void (*handler[LASTEvent]) (XEvent *) = { + [ButtonPress] = buttonpress, + [ClientMessage] = clientmessage, + [ConfigureRequest] = configurerequest, + [ConfigureNotify] = configurenotify, + [DestroyNotify] = destroynotify, + //[EnterNotify] = enternotify, + [Expose] = expose, + [FocusIn] = focusin, + [KeyPress] = keypress, + [MappingNotify] = mappingnotify, + [MapRequest] = maprequest, + [MotionNotify] = motionnotify, + [PropertyNotify] = propertynotify, + [ResizeRequest] = resizerequest, + [UnmapNotify] = unmapnotify +}; +static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; +static int running = 1; +static Cur *cursor[CurLast]; +static Clr **scheme; +static Display *dpy; +static Drw *drw; +static Monitor *mons, *selmon; +static Window root, wmcheckwin; + +/* configuration, allows nested code to access above variables */ +#include "config.h" + +/* compile-time check if all tags fit into an unsigned int bit array. */ +struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +/* function implementations */ +void +applyrules(Client *c) +{ + const char *class, *instance; + unsigned int i; + const Rule *r; + Monitor *m; + XClassHint ch = { NULL, NULL }; + + /* rule matching */ + c->isfloating = 0; + c->tags = 0; + XGetClassHint(dpy, c->win, &ch); + class = ch.res_class ? ch.res_class : broken; + instance = ch.res_name ? ch.res_name : broken; + + for (i = 0; i < LENGTH(rules); i++) { + r = &rules[i]; + if ((!r->title || strstr(c->name, r->title)) + && (!r->class || strstr(class, r->class)) + && (!r->instance || strstr(instance, r->instance))) + { + c->isfloating = r->isfloating; + c->tags |= r->tags; + for (m = mons; m && m->num != r->monitor; m = m->next); + if (m) + c->mon = m; + } + } + if (ch.res_class) + XFree(ch.res_class); + if (ch.res_name) + XFree(ch.res_name); + c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; +} + +int +applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) +{ + int baseismin; + Monitor *m = c->mon; + + /* set minimum possible */ + *w = MAX(1, *w); + *h = MAX(1, *h); + if (interact) { + if (*x > sw) + *x = sw - WIDTH(c); + if (*y > sh) + *y = sh - HEIGHT(c); + if (*x + *w + 2 * c->bw < 0) + *x = 0; + if (*y + *h + 2 * c->bw < 0) + *y = 0; + } else { + if (*x >= m->wx + m->ww) + *x = m->wx + m->ww - WIDTH(c); + if (*y >= m->wy + m->wh) + *y = m->wy + m->wh - HEIGHT(c); + if (*x + *w + 2 * c->bw <= m->wx) + *x = m->wx; + if (*y + *h + 2 * c->bw <= m->wy) + *y = m->wy; + } + if (*h < bh) + *h = bh; + if (*w < bh) + *w = bh; + if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { + /* see last two sentences in ICCCM 4.1.2.3 */ + baseismin = c->basew == c->minw && c->baseh == c->minh; + if (!baseismin) { /* temporarily remove base dimensions */ + *w -= c->basew; + *h -= c->baseh; + } + /* adjust for aspect limits */ + if (c->mina > 0 && c->maxa > 0) { + if (c->maxa < (float)*w / *h) + *w = *h * c->maxa + 0.5; + else if (c->mina < (float)*h / *w) + *h = *w * c->mina + 0.5; + } + if (baseismin) { /* increment calculation requires this */ + *w -= c->basew; + *h -= c->baseh; + } + /* adjust for increment value */ + if (c->incw) + *w -= *w % c->incw; + if (c->inch) + *h -= *h % c->inch; + /* restore base dimensions */ + *w = MAX(*w + c->basew, c->minw); + *h = MAX(*h + c->baseh, c->minh); + if (c->maxw) + *w = MIN(*w, c->maxw); + if (c->maxh) + *h = MIN(*h, c->maxh); + } + return *x != c->x || *y != c->y || *w != c->w || *h != c->h; +} + +void +arrange(Monitor *m) +{ + if (m) + showhide(m->stack); + else for (m = mons; m; m = m->next) + showhide(m->stack); + if (m) { + arrangemon(m); + restack(m); + } else for (m = mons; m; m = m->next) + arrangemon(m); +} + +void +arrangemon(Monitor *m) +{ + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); + if (m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); +} + +void +attach(Client *c) +{ + c->next = c->mon->clients; + c->mon->clients = c; +} + +void +attachstack(Client *c) +{ + c->snext = c->mon->stack; + c->mon->stack = c; +} + +void +buttonpress(XEvent *e) +{ + unsigned int i, x, click; + Arg arg = {0}; + Client *c; + Monitor *m; + XButtonPressedEvent *ev = &e->xbutton; + + click = ClkRootWin; + /* focus monitor if necessary */ + if ((m = wintomon(ev->window)) && m != selmon) { + unfocus(selmon->sel, 1); + selmon = m; + focus(NULL); + } + if (ev->window == selmon->barwin) { + i = x = 0; + 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 - TEXTW(stext) - getsystraywidth()) + click = ClkStatusText; + else + click = ClkWinTitle; + } else if ((c = wintoclient(ev->window))) { + focus(c); + restack(selmon); + XAllowEvents(dpy, ReplayPointer, CurrentTime); + click = ClkClientWin; + } + for (i = 0; i < LENGTH(buttons); i++) + if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button + && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) + buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); +} + +void +checkotherwm(void) +{ + xerrorxlib = XSetErrorHandler(xerrorstart); + /* this causes an error if some other window manager is running */ + XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask); + XSync(dpy, False); + XSetErrorHandler(xerror); + XSync(dpy, False); +} + +void +cleanup(void) +{ + Arg a = {.ui = ~0}; + Layout foo = { "", NULL }; + Monitor *m; + size_t i; + + view(&a); + selmon->lt[selmon->sellt] = &foo; + for (m = mons; m; m = m->next) + while (m->stack) + unmanage(m->stack, 0); + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); + if (showsystray) { + XUnmapWindow(dpy, systray->win); + XDestroyWindow(dpy, systray->win); + free(systray); + } + for (i = 0; i < CurLast; i++) + drw_cur_free(drw, cursor[i]); + for (i = 0; i < LENGTH(colors); i++) + free(scheme[i]); + XDestroyWindow(dpy, wmcheckwin); + drw_free(drw); + XSync(dpy, False); + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); +} + +void +cleanupmon(Monitor *mon) +{ + Monitor *m; + + if (mon == mons) + mons = mons->next; + else { + for (m = mons; m && m->next != mon; m = m->next); + m->next = mon->next; + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); + free(mon); +} + +void +clientmessage(XEvent *e) +{ + XWindowAttributes wa; + XSetWindowAttributes swa; + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); + + if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { + /* add systray icons */ + if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { + if (!(c = (Client *)calloc(1, sizeof(Client)))) + die("fatal: could not malloc() %u bytes\n", sizeof(Client)); + if (!(c->win = cme->data.l[2])) { + free(c); + return; + } + c->mon = selmon; + c->next = systray->icons; + systray->icons = c; + if (!XGetWindowAttributes(dpy, c->win, &wa)) { + /* use sane defaults */ + wa.width = bh; + wa.height = bh; + wa.border_width = 0; + } + c->x = c->oldx = c->y = c->oldy = 0; + c->w = c->oldw = wa.width; + c->h = c->oldh = wa.height; + c->oldbw = wa.border_width; + c->bw = 0; + c->isfloating = True; + /* reuse tags field as mapped status */ + c->tags = 1; + updatesizehints(c); + updatesystrayicongeom(c, wa.width, wa.height); + XAddToSaveSet(dpy, c->win); + XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); + 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); + /* 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]) { + if (cme->data.l[1] == netatom[NetWMFullscreen] + || cme->data.l[2] == netatom[NetWMFullscreen]) + setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */ + || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen))); + } else if (cme->message_type == netatom[NetActiveWindow]) { + if (c != selmon->sel && !c->isurgent) + seturgent(c, 1); + } +} + +void +configure(Client *c) +{ + XConfigureEvent ce; + + ce.type = ConfigureNotify; + ce.display = dpy; + ce.event = c->win; + ce.window = c->win; + ce.x = c->x; + ce.y = c->y; + ce.width = c->w; + ce.height = c->h; + ce.border_width = c->bw; + ce.above = None; + ce.override_redirect = False; + XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce); +} + +void +configurenotify(XEvent *e) +{ + Monitor *m; + Client *c; + XConfigureEvent *ev = &e->xconfigure; + int dirty; + + /* TODO: updategeom handling sucks, needs to be simplified */ + if (ev->window == root) { + dirty = (sw != ev->width || sh != ev->height); + sw = ev->width; + sh = ev->height; + if (updategeom() || dirty) { + drw_resize(drw, sw, bh); + updatebars(); + for (m = mons; m; m = m->next) { + for (c = m->clients; c; c = c->next) + if (c->isfullscreen) + resizeclient(c, m->mx, m->my, m->mw, m->mh); + resizebarwin(m); + } + focus(NULL); + arrange(NULL); + } + } +} + +void +configurerequest(XEvent *e) +{ + Client *c; + Monitor *m; + XConfigureRequestEvent *ev = &e->xconfigurerequest; + XWindowChanges wc; + + if ((c = wintoclient(ev->window))) { + if (ev->value_mask & CWBorderWidth) + c->bw = ev->border_width; + else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) { + m = c->mon; + if (ev->value_mask & CWX) { + c->oldx = c->x; + c->x = m->mx + ev->x; + } + if (ev->value_mask & CWY) { + c->oldy = c->y; + c->y = m->my + ev->y; + } + if (ev->value_mask & CWWidth) { + c->oldw = c->w; + c->w = ev->width; + } + if (ev->value_mask & CWHeight) { + c->oldh = c->h; + c->h = ev->height; + } + if ((c->x + c->w) > m->mx + m->mw && c->isfloating) + c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */ + if ((c->y + c->h) > m->my + m->mh && c->isfloating) + c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */ + if ((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight))) + configure(c); + if (ISVISIBLE(c)) + XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); + } else + configure(c); + } else { + wc.x = ev->x; + wc.y = ev->y; + wc.width = ev->width; + wc.height = ev->height; + wc.border_width = ev->border_width; + wc.sibling = ev->above; + wc.stack_mode = ev->detail; + XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); + } + XSync(dpy, False); +} + +Monitor * +createmon(void) +{ + Monitor *m; + + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; + m->mfact = mfact; + m->nmaster = nmaster; + m->showbar = showbar; + m->topbar = topbar; + m->gappx = gappx; + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); + return m; +} + +void +destroynotify(XEvent *e) +{ + Client *c; + XDestroyWindowEvent *ev = &e->xdestroywindow; + + if ((c = wintoclient(ev->window))) + unmanage(c, 1); + else if ((c = wintosystrayicon(ev->window))) { + removesystrayicon(c); + resizebarwin(selmon); + updatesystray(); + } +} + +void +detach(Client *c) +{ + Client **tc; + + for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next); + *tc = c->next; +} + +void +detachstack(Client *c) +{ + Client **tc, *t; + + for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext); + *tc = c->snext; + + if (c == c->mon->sel) { + for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext); + c->mon->sel = t; + } +} + +Monitor * +dirtomon(int dir) +{ + Monitor *m = NULL; + + if (dir > 0) { + if (!(m = selmon->next)) + m = mons; + } else if (selmon == mons) + for (m = mons; m->next; m = m->next); + else + for (m = mons; m->next != selmon; m = m->next); + return m; +} + +void +drawbar(Monitor *m) +{ + int x, w, sw = 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]); + sw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ + drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0); + } + + resizebarwin(m); + 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 ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); + if (occ & 1 << i) + drw_rect(drw, x + boxs, boxs, boxw, boxw, + m == selmon && selmon->sel && selmon->sel->tags & 1 << i, + urg & 1 << i); + x += w; + } + w = 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 - 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); + 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_map(drw, m->barwin, 0, 0, m->ww - stw, bh); +} + +void +drawbars(void) +{ + Monitor *m; + + for (m = mons; m; m = m->next) + drawbar(m); +} + +void +enternotify(XEvent *e) +{ + Client *c; + Monitor *m; + XCrossingEvent *ev = &e->xcrossing; + + if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root) + return; + c = wintoclient(ev->window); + m = c ? c->mon : wintomon(ev->window); + if (m != selmon) { + unfocus(selmon->sel, 1); + selmon = m; + } else if (!c || c == selmon->sel) + return; + focus(c); +} + +void +expose(XEvent *e) +{ + Monitor *m; + XExposeEvent *ev = &e->xexpose; + + if (ev->count == 0 && (m = wintomon(ev->window))) { + drawbar(m); + if (m == selmon) + updatesystray(); + } +} + +void +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); + if (c) { + if (c->mon != selmon) + selmon = c->mon; + if (c->isurgent) + seturgent(c, 0); + detachstack(c); + attachstack(c); + grabbuttons(c, 1); + XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); + setfocus(c); + } else { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); + } + selmon->sel = c; + drawbars(); +} + +/* there are some broken focus acquiring clients needing extra handling */ +void +focusin(XEvent *e) +{ + XFocusChangeEvent *ev = &e->xfocus; + + if (selmon->sel && ev->window != selmon->sel->win) + setfocus(selmon->sel); +} + +void +focusmon(const Arg *arg) +{ + Monitor *m; + + if (!mons->next) + return; + if ((m = dirtomon(arg->i)) == selmon) + return; + unfocus(selmon->sel, 0); + selmon = m; + focus(NULL); +} + +void +focusstack(const Arg *arg) +{ + Client *c = NULL, *i; + + if (!selmon->sel) + return; + if (arg->i > 0) { + for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); + if (!c) + for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); + } else { + for (i = selmon->clients; i != selmon->sel; i = i->next) + if (ISVISIBLE(i)) + c = i; + if (!c) + for (; i; i = i->next) + if (ISVISIBLE(i)) + c = i; + } + if (c) { + focus(c); + restack(selmon); + } +} + +Atom +getatomprop(Client *c, Atom prop) +{ + int di; + 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, 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; +} + +int +getrootptr(int *x, int *y) +{ + int di; + unsigned int dui; + Window dummy; + + return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui); +} + +long +getstate(Window w) +{ + int format; + long result = -1; + unsigned char *p = NULL; + unsigned long n, extra; + Atom real; + + if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState], + &real, &format, &n, &extra, (unsigned char **)&p) != Success) + return -1; + if (n != 0) + result = *p; + XFree(p); + return result; +} + +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) +{ + char **list = NULL; + int n; + XTextProperty name; + + if (!text || size == 0) + return 0; + text[0] = '\0'; + if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems) + return 0; + if (name.encoding == XA_STRING) + strncpy(text, (char *)name.value, size - 1); + else { + if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) { + strncpy(text, *list, size - 1); + XFreeStringList(list); + } + } + text[size - 1] = '\0'; + XFree(name.value); + return 1; +} + +void +grabbuttons(Client *c, int focused) +{ + updatenumlockmask(); + { + unsigned int i, j; + unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); + if (!focused) + XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, + BUTTONMASK, GrabModeSync, GrabModeSync, None, None); + for (i = 0; i < LENGTH(buttons); i++) + if (buttons[i].click == ClkClientWin) + for (j = 0; j < LENGTH(modifiers); j++) + XGrabButton(dpy, buttons[i].button, + buttons[i].mask | modifiers[j], + c->win, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, None); + } +} + +void +grabkeys(void) +{ + updatenumlockmask(); + { + unsigned int i, j; + unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; + KeyCode code; + + XUngrabKey(dpy, AnyKey, AnyModifier, root); + for (i = 0; i < LENGTH(keys); i++) + if ((code = XKeysymToKeycode(dpy, keys[i].keysym))) + for (j = 0; j < LENGTH(modifiers); j++) + XGrabKey(dpy, code, keys[i].mod | modifiers[j], root, + True, GrabModeAsync, GrabModeAsync); + } +} + +void +incnmaster(const Arg *arg) +{ + selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); +} + +#ifdef XINERAMA +static int +isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) +{ + while (n--) + if (unique[n].x_org == info->x_org && unique[n].y_org == info->y_org + && unique[n].width == info->width && unique[n].height == info->height) + return 0; + return 1; +} +#endif /* XINERAMA */ + +void +keypress(XEvent *e) +{ + unsigned int i; + KeySym keysym; + XKeyEvent *ev; + + ev = &e->xkey; + keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); + for (i = 0; i < LENGTH(keys); i++) + if (keysym == keys[i].keysym + && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) + && keys[i].func) + keys[i].func(&(keys[i].arg)); +} + +void +killclient(const Arg *arg) +{ + if (!selmon->sel) + return; + if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { + XGrabServer(dpy); + XSetErrorHandler(xerrordummy); + XSetCloseDownMode(dpy, DestroyAll); + XKillClient(dpy, selmon->sel->win); + XSync(dpy, False); + XSetErrorHandler(xerror); + XUngrabServer(dpy); + } +} + +void +manage(Window w, XWindowAttributes *wa) +{ + Client *c, *t = NULL; + Window trans = None; + XWindowChanges wc; + + c = ecalloc(1, sizeof(Client)); + c->win = w; + /* geometry */ + c->x = c->oldx = wa->x; + c->y = c->oldy = wa->y; + c->w = c->oldw = wa->width; + c->h = c->oldh = wa->height; + c->oldbw = wa->border_width; + + updatetitle(c); + if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { + c->mon = t->mon; + c->tags = t->tags; + } else { + c->mon = selmon; + applyrules(c); + } + + if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw) + c->x = c->mon->mx + c->mon->mw - WIDTH(c); + if (c->y + HEIGHT(c) > c->mon->my + c->mon->mh) + 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->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); + configure(c); /* propagates border_width, if size doesn't change */ + updatewindowtype(c); + updatesizehints(c); + updatewmhints(c); + XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); + grabbuttons(c, 0); + if (!c->isfloating) + c->isfloating = c->oldstate = trans != None || c->isfixed; + if (c->isfloating) + XRaiseWindow(dpy, c->win); + attach(c); + attachstack(c); + XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); + XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ + setclientstate(c, NormalState); + if (c->mon == selmon) + unfocus(selmon->sel, 0); + c->mon->sel = c; + arrange(c->mon); + XMapWindow(dpy, c->win); + focus(NULL); +} + +void +mappingnotify(XEvent *e) +{ + XMappingEvent *ev = &e->xmapping; + + XRefreshKeyboardMapping(ev); + if (ev->request == MappingKeyboard) + grabkeys(); +} + +void +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; + if (wa.override_redirect) + return; + 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); +} + +void +motionnotify(XEvent *e) +{ + static Monitor *mon = NULL; + Monitor *m; + XMotionEvent *ev = &e->xmotion; + + if (ev->window != root) + return; + if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { + unfocus(selmon->sel, 1); + selmon = m; + focus(NULL); + } + mon = m; +} + +void +movemouse(const Arg *arg) +{ + int x, y, ocx, ocy, nx, ny; + Client *c; + Monitor *m; + XEvent ev; + Time lasttime = 0; + + if (!(c = selmon->sel)) + return; + if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ + return; + restack(selmon); + ocx = c->x; + ocy = c->y; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, + None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) + return; + if (!getrootptr(&x, &y)) + return; + do { + XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); + switch(ev.type) { + case ConfigureRequest: + case Expose: + case MapRequest: + handler[ev.type](&ev); + break; + case MotionNotify: + if ((ev.xmotion.time - lasttime) <= (1000 / 60)) + continue; + lasttime = ev.xmotion.time; + + nx = ocx + (ev.xmotion.x - x); + ny = ocy + (ev.xmotion.y - y); + if (abs(selmon->wx - nx) < snap) + nx = selmon->wx; + else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) + nx = selmon->wx + selmon->ww - WIDTH(c); + if (abs(selmon->wy - ny) < snap) + ny = selmon->wy; + else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap) + ny = selmon->wy + selmon->wh - HEIGHT(c); + if (!c->isfloating && selmon->lt[selmon->sellt]->arrange + && (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) + togglefloating(NULL); + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) + resize(c, nx, ny, c->w, c->h, 1); + break; + } + } while (ev.type != ButtonRelease); + XUngrabPointer(dpy, CurrentTime); + if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { + sendmon(c, m); + selmon = m; + focus(NULL); + } +} + +Client * +nexttiled(Client *c) +{ + for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); + return c; +} + +void +pop(Client *c) +{ + detach(c); + attach(c); + focus(c); + arrange(c->mon); +} + +void +propertynotify(XEvent *e) +{ + Client *c; + 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) + return; /* ignore */ + else if ((c = wintoclient(ev->window))) { + switch(ev->atom) { + default: break; + case XA_WM_TRANSIENT_FOR: + if (!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) && + (c->isfloating = (wintoclient(trans)) != NULL)) + arrange(c->mon); + break; + case XA_WM_NORMAL_HINTS: + updatesizehints(c); + break; + case XA_WM_HINTS: + updatewmhints(c); + drawbars(); + break; + } + if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { + updatetitle(c); + if (c == c->mon->sel) + drawbar(c->mon); + } + if (ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); + } +} + +void +quit(const Arg *arg) +{ + running = 0; +} + +Monitor * +recttomon(int x, int y, int w, int h) +{ + Monitor *m, *r = selmon; + int a, area = 0; + + for (m = mons; m; m = m->next) + if ((a = INTERSECT(x, y, w, h, m)) > area) { + area = a; + r = m; + } + return r; +} + +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) +{ + if (applysizehints(c, &x, &y, &w, &h, 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) +{ + XWindowChanges wc; + + c->oldx = c->x; c->x = wc.x = x; + c->oldy = c->y; c->y = wc.y = y; + c->oldw = c->w; c->w = wc.width = w; + c->oldh = c->h; c->h = wc.height = h; + wc.border_width = c->bw; + XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); + configure(c); + XSync(dpy, False); +} + +void +resizemouse(const Arg *arg) +{ + int ocx, ocy, nw, nh; + Client *c; + Monitor *m; + XEvent ev; + Time lasttime = 0; + + if (!(c = selmon->sel)) + return; + if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ + return; + restack(selmon); + ocx = c->x; + ocy = c->y; + 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); + 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; + + nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); + nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); + if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww + && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh) + { + if (!c->isfloating && selmon->lt[selmon->sellt]->arrange + && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) + togglefloating(NULL); + } + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) + resize(c, c->x, c->y, nw, nh, 1); + break; + } + } while (ev.type != ButtonRelease); + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); + XUngrabPointer(dpy, CurrentTime); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); + if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { + sendmon(c, m); + selmon = m; + focus(NULL); + } +} + +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) +{ + Client *c; + XEvent ev; + XWindowChanges wc; + + drawbar(m); + if (!m->sel) + return; + if (m->sel->isfloating || !m->lt[m->sellt]->arrange) + XRaiseWindow(dpy, m->sel->win); + if (m->lt[m->sellt]->arrange) { + wc.stack_mode = Below; + wc.sibling = m->barwin; + for (c = m->stack; c; c = c->snext) + if (!c->isfloating && ISVISIBLE(c)) { + XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc); + wc.sibling = c->win; + } + } + XSync(dpy, False); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); +} + +void +run(void) +{ + XEvent ev; + /* main event loop */ + XSync(dpy, False); + while (running && !XNextEvent(dpy, &ev)) + if (handler[ev.type]) + handler[ev.type](&ev); /* call handler */ +} + +void +scan(void) +{ + unsigned int i, num; + Window d1, d2, *wins = NULL; + XWindowAttributes wa; + + if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { + for (i = 0; i < num; i++) { + if (!XGetWindowAttributes(dpy, wins[i], &wa) + || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) + continue; + if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) + manage(wins[i], &wa); + } + for (i = 0; i < num; i++) { /* now the transients */ + if (!XGetWindowAttributes(dpy, wins[i], &wa)) + continue; + if (XGetTransientForHint(dpy, wins[i], &d1) + && (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)) + manage(wins[i], &wa); + } + if (wins) + XFree(wins); + } +} + +void +sendmon(Client *c, Monitor *m) +{ + if (c->mon == m) + return; + unfocus(c, 1); + detach(c); + detachstack(c); + c->mon = m; + c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ + attach(c); + attachstack(c); + focus(NULL); + arrange(NULL); +} + +void +setclientstate(Client *c, long state) +{ + long data[] = { state, None }; + + XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, + PropModeReplace, (unsigned char *)data, 2); +} + +int +sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) +{ + int n; + Atom *protocols, mt; + int exists = 0; + XEvent ev; + + 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 = 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); + } + return exists; +} + +void +setfocus(Client *c) +{ + if (!c->neverfocus) { + XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); + XChangeProperty(dpy, root, netatom[NetActiveWindow], + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(c->win), 1); + } + sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); +} + +void +setfullscreen(Client *c, int fullscreen) +{ + if (fullscreen && !c->isfullscreen) { + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, + PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); + c->isfullscreen = 1; + c->oldstate = c->isfloating; + c->oldbw = c->bw; + c->bw = 0; + c->isfloating = 1; + resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); + XRaiseWindow(dpy, c->win); + } else if (!fullscreen && c->isfullscreen){ + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, + PropModeReplace, (unsigned char*)0, 0); + c->isfullscreen = 0; + c->isfloating = c->oldstate; + c->bw = c->oldbw; + c->x = c->oldx; + c->y = c->oldy; + c->w = c->oldw; + c->h = c->oldh; + resizeclient(c, c->x, c->y, c->w, c->h); + arrange(c->mon); + } +} + +void +setgaps(const Arg *arg) +{ + if ((arg->i == 0) || (selmon->gappx + arg->i < 0)) + selmon->gappx = 0; + else + selmon->gappx += arg->i; + arrange(selmon); +} + +void +setlayout(const Arg *arg) +{ + if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) + selmon->sellt ^= 1; + if (arg && arg->v) + selmon->lt[selmon->sellt] = (Layout *)arg->v; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if (selmon->sel) + arrange(selmon); + else + drawbar(selmon); +} + +/* arg > 1.0 will set mfact absolutely */ +void +setmfact(const Arg *arg) +{ + float f; + + if (!arg || !selmon->lt[selmon->sellt]->arrange) + return; + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if (f < 0.1 || f > 0.9) + return; + selmon->mfact = f; + arrange(selmon); +} + +void +setup(void) +{ + int i; + XSetWindowAttributes wa; + Atom utf8string; + + /* clean up any zombies immediately */ + sigchld(0); + + /* init screen */ + screen = DefaultScreen(dpy); + sw = DisplayWidth(dpy, screen); + sh = DisplayHeight(dpy, screen); + root = RootWindow(dpy, screen); + 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; + updategeom(); + /* init atoms */ + utf8string = XInternAtom(dpy, "UTF8_STRING", False); + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); + wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); + wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); + netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); + netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); + netatom[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); + 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); + 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); + cursor[CurMove] = drw_cur_create(drw, XC_fleur); + /* init appearance */ + scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); + for (i = 0; i < LENGTH(colors); i++) + scheme[i] = drw_scm_create(drw, colors[i], 3); + /* init system tray */ + updatesystray(); + /* init bars */ + updatebars(); + updatestatus(); + /* supporting window for NetWMCheck */ + wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0); + XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32, + PropModeReplace, (unsigned char *) &wmcheckwin, 1); + XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8, + PropModeReplace, (unsigned char *) "dwm", 3); + XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32, + PropModeReplace, (unsigned char *) &wmcheckwin, 1); + /* EWMH support per view */ + XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, + PropModeReplace, (unsigned char *) netatom, NetLast); + XDeleteProperty(dpy, root, netatom[NetClientList]); + /* select events */ + wa.cursor = cursor[CurNormal]->cursor; + wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask + |ButtonPressMask|PointerMotionMask|EnterWindowMask + |LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; + XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); + XSelectInput(dpy, root, wa.event_mask); + grabkeys(); + focus(NULL); +} + + +void +seturgent(Client *c, int urg) +{ + XWMHints *wmh; + + c->isurgent = urg; + if (!(wmh = XGetWMHints(dpy, c->win))) + return; + wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint); + XSetWMHints(dpy, c->win, wmh); + XFree(wmh); +} + +void +showhide(Client *c) +{ + if (!c) + return; + if (ISVISIBLE(c)) { + /* show clients top down */ + XMoveWindow(dpy, c->win, c->x, c->y); + if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen) + resize(c, c->x, c->y, c->w, c->h, 0); + showhide(c->snext); + } else { + /* hide clients bottom up */ + showhide(c->snext); + XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y); + } +} + +void +sigchld(int unused) +{ + if (signal(SIGCHLD, sigchld) == SIG_ERR) + die("can't install SIGCHLD handler:"); + while (0 < waitpid(-1, NULL, WNOHANG)); +} + +void +spawn(const Arg *arg) +{ + if (arg->v == dmenucmd) + dmenumon[0] = '0' + selmon->num; + if (fork() == 0) { + if (dpy) + close(ConnectionNumber(dpy)); + setsid(); + execvp(((char **)arg->v)[0], (char **)arg->v); + fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]); + perror(" failed"); + exit(EXIT_SUCCESS); + } +} + +void +tag(const Arg *arg) +{ + if (selmon->sel && arg->ui & TAGMASK) { + selmon->sel->tags = arg->ui & TAGMASK; + focus(NULL); + arrange(selmon); + } +} + +void +tagmon(const Arg *arg) +{ + if (!selmon->sel || !mons->next) + return; + sendmon(selmon->sel, dirtomon(arg->i)); +} + +void +tile(Monitor *m) +{ + unsigned int i, n, h, mw, my, ty; + Client *c; + + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if (n == 0) + return; + + if (n > m->nmaster) + mw = m->nmaster ? m->ww * m->mfact : 0; + else + mw = m->ww - m->gappx; + for (i = 0, my = ty = m->gappx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { + h = (m->wh - my) / (MIN(n, m->nmaster) - i) - m->gappx; + resize(c, m->wx + m->gappx, m->wy + my, mw - (2*c->bw) - m->gappx, h - (2*c->bw), 0); + my += HEIGHT(c) + m->gappx; + } else { + h = (m->wh - ty) / (n - i) - m->gappx; + resize(c, m->wx + mw + m->gappx, m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->gappx, h - (2*c->bw), 0); + ty += HEIGHT(c) + m->gappx; + } +} + +void +togglebar(const Arg *arg) +{ + selmon->showbar = !selmon->showbar; + updatebarpos(selmon); + 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); +} + +void +togglefloating(const Arg *arg) +{ + if (!selmon->sel) + return; + if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ + return; + selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed; + if (selmon->sel->isfloating) + resize(selmon->sel, selmon->sel->x, selmon->sel->y, + selmon->sel->w, selmon->sel->h, 0); + arrange(selmon); +} + +void +toggletag(const Arg *arg) +{ + unsigned int newtags; + + if (!selmon->sel) + return; + newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); + if (newtags) { + selmon->sel->tags = newtags; + focus(NULL); + arrange(selmon); + } +} + +void +toggleview(const Arg *arg) +{ + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + + if (newtagset) { + selmon->tagset[selmon->seltags] = newtagset; + focus(NULL); + arrange(selmon); + } +} + +void +unfocus(Client *c, int setfocus) +{ + if (!c) + return; + grabbuttons(c, 0); + XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); + if (setfocus) { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); + } +} + +void +unmanage(Client *c, int destroyed) +{ + Monitor *m = c->mon; + XWindowChanges wc; + + detach(c); + detachstack(c); + if (!destroyed) { + wc.border_width = c->oldbw; + XGrabServer(dpy); /* avoid race conditions */ + XSetErrorHandler(xerrordummy); + XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */ + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); + setclientstate(c, WithdrawnState); + XSync(dpy, False); + XSetErrorHandler(xerror); + XUngrabServer(dpy); + } + free(c); + focus(NULL); + updateclientlist(); + arrange(m); +} + +void +unmapnotify(XEvent *e) +{ + Client *c; + XUnmapEvent *ev = &e->xunmap; + + if ((c = wintoclient(ev->window))) { + if (ev->send_event) + setclientstate(c, WithdrawnState); + 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, + .background_pixmap = ParentRelative, + .event_mask = ButtonPressMask|ExposureMask + }; + XClassHint ch = {"dwm", "dwm"}; + for (m = mons; m; m = m->next) { + if (m->barwin) + continue; + 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); + } +} + +void +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; + } else + m->by = -bh; +} + +void +updateclientlist() +{ + Client *c; + Monitor *m; + + XDeleteProperty(dpy, root, netatom[NetClientList]); + for (m = mons; m; m = m->next) + for (c = m->clients; c; c = c->next) + XChangeProperty(dpy, root, netatom[NetClientList], + XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); +} + +int +updategeom(void) +{ + int dirty = 0; + +#ifdef XINERAMA + if (XineramaIsActive(dpy)) { + int i, j, n, nn; + Client *c; + Monitor *m; + XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn); + XineramaScreenInfo *unique = NULL; + + for (n = 0, m = mons; m; m = m->next, n++); + /* only consider unique geometries as separate screens */ + unique = ecalloc(nn, sizeof(XineramaScreenInfo)); + for (i = 0, j = 0; i < nn; i++) + if (isuniquegeom(unique, j, &info[i])) + memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo)); + XFree(info); + nn = j; + if (n <= nn) { /* new monitors available */ + for (i = 0; i < (nn - n); i++) { + for (m = mons; m && m->next; m = m->next); + if (m) + m->next = createmon(); + else + mons = createmon(); + } + for (i = 0, m = mons; i < nn && m; m = m->next, i++) + if (i >= n + || unique[i].x_org != m->mx || unique[i].y_org != m->my + || unique[i].width != m->mw || unique[i].height != m->mh) + { + dirty = 1; + m->num = i; + m->mx = m->wx = unique[i].x_org; + m->my = m->wy = unique[i].y_org; + m->mw = m->ww = unique[i].width; + m->mh = m->wh = unique[i].height; + updatebarpos(m); + } + } else { /* less monitors available nn < n */ + for (i = nn; i < n; i++) { + for (m = mons; m && m->next; m = m->next); + while ((c = m->clients)) { + dirty = 1; + m->clients = c->next; + detachstack(c); + c->mon = mons; + attach(c); + attachstack(c); + } + if (m == selmon) + selmon = mons; + cleanupmon(m); + } + } + free(unique); + } else +#endif /* XINERAMA */ + { /* default monitor setup */ + if (!mons) + mons = createmon(); + if (mons->mw != sw || mons->mh != sh) { + dirty = 1; + mons->mw = mons->ww = sw; + mons->mh = mons->wh = sh; + updatebarpos(mons); + } + } + if (dirty) { + selmon = mons; + selmon = wintomon(root); + } + return dirty; +} + +void +updatenumlockmask(void) +{ + unsigned int i, j; + XModifierKeymap *modmap; + + numlockmask = 0; + modmap = XGetModifierMapping(dpy); + for (i = 0; i < 8; i++) + for (j = 0; j < modmap->max_keypermod; j++) + if (modmap->modifiermap[i * modmap->max_keypermod + j] + == XKeysymToKeycode(dpy, XK_Num_Lock)) + numlockmask = (1 << i); + XFreeModifiermap(modmap); +} + +void +updatesizehints(Client *c) +{ + long msize; + XSizeHints size; + + if (!XGetWMNormalHints(dpy, c->win, &size, &msize)) + /* size is uninitialized, ensure that size.flags aren't used */ + size.flags = PSize; + if (size.flags & PBaseSize) { + c->basew = size.base_width; + c->baseh = size.base_height; + } else if (size.flags & PMinSize) { + c->basew = size.min_width; + c->baseh = size.min_height; + } else + c->basew = c->baseh = 0; + if (size.flags & PResizeInc) { + c->incw = size.width_inc; + c->inch = size.height_inc; + } else + c->incw = c->inch = 0; + if (size.flags & PMaxSize) { + c->maxw = size.max_width; + c->maxh = size.max_height; + } else + c->maxw = c->maxh = 0; + if (size.flags & PMinSize) { + c->minw = size.min_width; + c->minh = size.min_height; + } else if (size.flags & PBaseSize) { + c->minw = size.base_width; + c->minh = size.base_height; + } else + c->minw = c->minh = 0; + if (size.flags & PAspect) { + c->mina = (float)size.min_aspect.y / size.min_aspect.x; + c->maxa = (float)size.max_aspect.x / size.max_aspect.y; + } else + c->maxa = c->mina = 0.0; + c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh); +} + +void +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 +updatetitle(Client *c) +{ + if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name)) + gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name); + if (c->name[0] == '\0') /* hack to mark broken clients */ + strcpy(c->name, broken); +} + +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; +} + +void +updatewmhints(Client *c) +{ + XWMHints *wmh; + + if ((wmh = XGetWMHints(dpy, c->win))) { + if (c == selmon->sel && wmh->flags & XUrgencyHint) { + wmh->flags &= ~XUrgencyHint; + XSetWMHints(dpy, c->win, wmh); + } else + c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0; + if (wmh->flags & InputHint) + c->neverfocus = !wmh->input; + else + c->neverfocus = 0; + XFree(wmh); + } +} + +void +view(const Arg *arg) +{ + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ + if (arg->ui & TAGMASK) + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + focus(NULL); + arrange(selmon); +} + +Client * +wintoclient(Window w) +{ + Client *c; + Monitor *m; + + for (m = mons; m; m = m->next) + for (c = m->clients; c; c = c->next) + if (c->win == w) + return c; + return NULL; +} + +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) +{ + int x, y; + Client *c; + Monitor *m; + + if (w == root && getrootptr(&x, &y)) + return recttomon(x, y, 1, 1); + for (m = mons; m; m = m->next) + if (w == m->barwin) + return m; + if ((c = wintoclient(w))) + return c->mon; + return selmon; +} + +/* 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. */ +int +xerror(Display *dpy, XErrorEvent *ee) +{ + if (ee->error_code == BadWindow + || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch) + || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable) + || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable) + || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable) + || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch) + || (ee->request_code == X_GrabButton && ee->error_code == BadAccess) + || (ee->request_code == X_GrabKey && ee->error_code == BadAccess) + || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable)) + return 0; + fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n", + ee->request_code, ee->error_code); + return xerrorxlib(dpy, ee); /* may call exit */ +} + +int +xerrordummy(Display *dpy, XErrorEvent *ee) +{ + return 0; +} + +/* Startup Error handler to check if another window manager + * is already running. */ +int +xerrorstart(Display *dpy, XErrorEvent *ee) +{ + die("dwm: another window manager is already running"); + return -1; +} + +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) +{ + Client *c = selmon->sel; + + if (!selmon->lt[selmon->sellt]->arrange + || (selmon->sel && selmon->sel->isfloating)) + return; + if (c == nexttiled(selmon->clients)) + if (!c || !(c = nexttiled(c->next))) + return; + pop(c); +} + +int +main(int argc, char *argv[]) +{ + if (argc == 2 && !strcmp("-v", argv[1])) + die("dwm-"VERSION); + else if (argc != 1) + die("usage: dwm [-v]"); + if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) + fputs("warning: no locale support\n", stderr); + if (!(dpy = XOpenDisplay(NULL))) + die("dwm: cannot open display"); + checkotherwm(); + setup(); +#ifdef __OpenBSD__ + if (pledge("stdio rpath proc exec", NULL) == -1) + die("pledge"); +#endif /* __OpenBSD__ */ + scan(); + run(); + cleanup(); + XCloseDisplay(dpy); + return EXIT_SUCCESS; +} diff --git a/stuff/manual-programs/suckless/dwm/dwm.o b/stuff/manual-programs/suckless/dwm/dwm.o new file mode 100644 index 0000000000000000000000000000000000000000..fd58ec3584ea8237d1e6147be0d64ed4308cf5d8 GIT binary patch literal 69688 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 literal 0 HcmV?d00001 diff --git a/stuff/manual-programs/suckless/dwm/dwm.png b/stuff/manual-programs/suckless/dwm/dwm.png new file mode 100644 index 0000000000000000000000000000000000000000..b1f9ba7e5f4cc7350ee2392ebcea5fcbe00fb49b GIT binary patch literal 373 zcmeAS@N?(olHy`uVBq!ia0vp^2Y@($g9*gC@m3f}u_bxCyDx`7I;J! zGca%iWx0hJ8D`Cq01C2~c>21sUt<^MF=V?Ztt9{yk}YwKC~?lu%}vcKVQ?-=O)N=G zQ7F$W$xsN%NL6t6^bL5QqM8R(c+=CxF{I+w+q;fj4F)_6j>`Z3pZ>_($QEQ&92OXP z%lpEKGwG8$G-U1H{@Y%;mx-mNK|p|siBVAj$Z~Mt-~h6K0!}~{PyozQ07(f5fTdVi zm=-zT`NweeJ#%S&{fequZGmkDDC*%x$$Sa*fAP=$`nJkhx1Y~k<8b2;Hq)FOdV=P$ q&oWzoxz_&nv&n0)xBzV8k*jsxheTIy&cCY600f?{elF{r5}E*x)opSB literal 0 HcmV?d00001 diff --git a/stuff/manual-programs/suckless/dwm/dwmstatus/LICENSE b/stuff/manual-programs/suckless/dwm/dwmstatus/LICENSE new file mode 100644 index 0000000..855608d --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/dwmstatus/LICENSE @@ -0,0 +1,21 @@ +MIT/X Consortium License + +© 2011-2018 Christoph Lohmann <20h@r-36.net> + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/stuff/manual-programs/suckless/dwm/dwmstatus/Makefile b/stuff/manual-programs/suckless/dwm/dwmstatus/Makefile new file mode 100644 index 0000000..62240a5 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/dwmstatus/Makefile @@ -0,0 +1,49 @@ +# See LICENSE file for copyright and license details. + +include config.mk + +SRC = ${NAME}.c +OBJ = ${SRC:.c=.o} + +all: options ${NAME} + +options: + @echo ${NAME} build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +.c.o: + @echo CC $< + @${CC} -c ${CFLAGS} $< + +${OBJ}: config.mk + +${NAME}: ${OBJ} + @echo CC -o $@ + @${CC} -o $@ ${OBJ} ${LDFLAGS} + +clean: + @echo cleaning + @rm -f ${NAME} ${OBJ} ${NAME}-${VERSION}.tar.gz + +dist: clean + @echo creating dist tarball + @mkdir -p ${NAME}-${VERSION} + @cp -R Makefile LICENSE config.mk \ + ${SRC} ${NAME}-${VERSION} + @tar -cf ${NAME}-${VERSION}.tar ${NAME}-${VERSION} + @gzip ${NAME}-${VERSION}.tar + @rm -rf ${NAME}-${VERSION} + +install: all + @echo installing executable file to ${DESTDIR}${PREFIX}/bin + @mkdir -p ${DESTDIR}${PREFIX}/bin + @cp -f ${NAME} ${DESTDIR}${PREFIX}/bin + @chmod 755 ${DESTDIR}${PREFIX}/bin/${NAME} + +uninstall: + @echo removing executable file from ${DESTDIR}${PREFIX}/bin + @rm -f ${DESTDIR}${PREFIX}/bin/${NAME} + +.PHONY: all options clean dist install uninstall diff --git a/stuff/manual-programs/suckless/dwm/dwmstatus/config.mk b/stuff/manual-programs/suckless/dwm/dwmstatus/config.mk new file mode 100644 index 0000000..0ec9e47 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/dwmstatus/config.mk @@ -0,0 +1,30 @@ +NAME = dwmstatus +VERSION = 1.0 + +# Customize below to fit your system + +# paths +PREFIX = /usr +MANPREFIX = ${PREFIX}/share/man + +X11INC = /usr/X11R6/include +X11LIB = /usr/X11R6/lib + +# includes and libs +INCS = -I. -I/usr/include -I${X11INC} +LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 + +# flags +CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE +CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} +#CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} +LDFLAGS = -g ${LIBS} +#LDFLAGS = -s ${LIBS} + +# Solaris +#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\" +#LDFLAGS = ${LIBS} + +# compiler and linker +CC = cc + diff --git a/stuff/manual-programs/suckless/dwm/dwmstatus/dwmstatus-temperature.c b/stuff/manual-programs/suckless/dwm/dwmstatus/dwmstatus-temperature.c new file mode 100644 index 0000000..13f27f6 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/dwmstatus/dwmstatus-temperature.c @@ -0,0 +1,15 @@ +/* + * gettemperature("/sys/class/hwmon/hwmon0/device", "temp1_input"); + */ + +char * +gettemperature(char *base, char *sensor) +{ + char *co; + + co = readfile(base, sensor); + if (co == NULL) + return smprintf(""); + return smprintf("%02.0f°C", atof(co) / 1000); +} + diff --git a/stuff/manual-programs/suckless/dwm/dwmstatus/dwmstatus.c b/stuff/manual-programs/suckless/dwm/dwmstatus/dwmstatus.c new file mode 100644 index 0000000..d2a4b03 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/dwmstatus/dwmstatus.c @@ -0,0 +1,227 @@ +/* + * Copy me if you can. + * by 20h + */ + +#define _BSD_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +char *tzargentina = "America/Buenos_Aires"; +char *tzutc = "UTC"; +char *tzberlin = "Europe/Berlin"; + +static Display *dpy; + +char * +smprintf(char *fmt, ...) +{ + va_list fmtargs; + char *ret; + int len; + + va_start(fmtargs, fmt); + len = vsnprintf(NULL, 0, fmt, fmtargs); + va_end(fmtargs); + + ret = malloc(++len); + if (ret == NULL) { + perror("malloc"); + exit(1); + } + + va_start(fmtargs, fmt); + vsnprintf(ret, len, fmt, fmtargs); + va_end(fmtargs); + + return ret; +} + +void +settz(char *tzname) +{ + setenv("TZ", tzname, 1); +} + +char * +mktimes(char *fmt, char *tzname) +{ + char buf[129]; + time_t tim; + struct tm *timtm; + + settz(tzname); + tim = time(NULL); + timtm = localtime(&tim); + if (timtm == NULL) + return smprintf(""); + + if (!strftime(buf, sizeof(buf)-1, fmt, timtm)) { + fprintf(stderr, "strftime == 0\n"); + return smprintf(""); + } + + return smprintf("%s", buf); +} + +void +setstatus(char *str) +{ + XStoreName(dpy, DefaultRootWindow(dpy), str); + XSync(dpy, False); +} + +char * +loadavg(void) +{ + double avgs[3]; + + if (getloadavg(avgs, 3) < 0) + return smprintf(""); + + return smprintf("%.2f %.2f %.2f", avgs[0], avgs[1], avgs[2]); +} + +char * +readfile(char *base, char *file) +{ + char *path, line[513]; + FILE *fd; + + memset(line, 0, sizeof(line)); + + path = smprintf("%s/%s", base, file); + fd = fopen(path, "r"); + free(path); + if (fd == NULL) + return NULL; + + if (fgets(line, sizeof(line)-1, fd) == NULL) + return NULL; + fclose(fd); + + return smprintf("%s", line); +} + +char * +getbattery(char *base) +{ + char *co, status; + int descap, remcap; + + descap = -1; + remcap = -1; + + co = readfile(base, "present"); + if (co == NULL) + return smprintf(""); + if (co[0] != '1') { + free(co); + return smprintf("not present"); + } + free(co); + + co = readfile(base, "charge_full_design"); + if (co == NULL) { + co = readfile(base, "energy_full_design"); + if (co == NULL) + return smprintf(""); + } + sscanf(co, "%d", &descap); + free(co); + + co = readfile(base, "charge_now"); + if (co == NULL) { + co = readfile(base, "energy_now"); + if (co == NULL) + return smprintf(""); + } + sscanf(co, "%d", &remcap); + free(co); + + co = readfile(base, "status"); + if (!strncmp(co, "Discharging", 11)) { + status = '-'; + } else if(!strncmp(co, "Charging", 8)) { + status = '+'; + } else { + status = '?'; + } + + if (remcap < 0 || descap < 0) + return smprintf("invalid"); + + return smprintf("%.0f%%%c", ((float)remcap / (float)descap) * 100, status); +} + +char * +gettemperature(char *base, char *sensor) +{ + char *co; + + co = readfile(base, sensor); + if (co == NULL) + return smprintf(""); + return smprintf("%02.0f°C", atof(co) / 1000); +} + +int +main(void) +{ + char *status; + char *avgs; + char *bat; + char *bat1; + char *tmar; + char *tmutc; + char *tmbln; + char *t0, *t1, *t2; + + if (!(dpy = XOpenDisplay(NULL))) { + fprintf(stderr, "dwmstatus: cannot open display.\n"); + return 1; + } + + for (;;sleep(60)) { + avgs = loadavg(); + bat = getbattery("/sys/class/power_supply/BAT0"); + bat1 = getbattery("/sys/class/power_supply/BAT1"); + tmar = mktimes("%H:%M", tzargentina); + tmutc = mktimes("%H:%M", tzutc); + tmbln = mktimes("KW %W %a %d %b %H:%M %Z %Y", tzberlin); + t0 = gettemperature("/sys/devices/virtual/hwmon/hwmon0", "temp1_input"); + t1 = gettemperature("/sys/devices/virtual/hwmon/hwmon2", "temp1_input"); + t2 = gettemperature("/sys/devices/virtual/hwmon/hwmon4", "temp1_input"); + + status = smprintf("T:%s|%s|%s L:%s B:%s|%s A:%s U:%s %s", + t0, t1, t2, avgs, bat, bat1, tmar, tmutc, + tmbln); + setstatus(status); + + free(t0); + free(t1); + free(t2); + free(avgs); + free(bat); + free(bat1); + free(tmar); + free(tmutc); + free(tmbln); + free(status); + } + + XCloseDisplay(dpy); + + return 0; +} + diff --git a/stuff/manual-programs/suckless/dwm/dwmstatus/new-acpi-battery.c b/stuff/manual-programs/suckless/dwm/dwmstatus/new-acpi-battery.c new file mode 100644 index 0000000..cda0084 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/dwmstatus/new-acpi-battery.c @@ -0,0 +1,55 @@ +char * +readfile(char *base, char *file) +{ + char *path, line[513]; + FILE *fd; + + memset(line, 0, sizeof(line)); + + path = smprintf("%s/%s", base, file); + fd = fopen(path, "r"); + if (fd == NULL) { + perror("fopen"); + exit(1); + } + free(path); + + if (fgets(line, sizeof(line)-1, fd) == NULL) { + perror("fgets"); + exit(1); + } + fclose(fd); + + return smprintf("%s", line); +} + +char * +getbattery(char *base) +{ + char *co; + int descap, remcap; + + descap = -1; + remcap = -1; + + co = readfile(base, "present"); + if (co[0] != '1') { + free(co); + return smprintf("not present"); + } + free(co); + + co = readfile(base, "charge_full_design"); + sscanf(co, "%d", &descap); + free(co); + + co = readfile(base, "charge_now"); + sscanf(co, "%d", &remcap); + free(co); + + if (remcap < 0 || descap < 0) + return smprintf("invalid"); + + return smprintf("%.0f", ((float)remcap / (float)descap) * 100); +} + diff --git a/stuff/manual-programs/suckless/dwm/endx b/stuff/manual-programs/suckless/dwm/endx new file mode 100644 index 0000000..982d44f --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/endx @@ -0,0 +1,5 @@ +#!/bin/sh +#gives you a dmenu prompt to confirm if you want to exit X + +[ $(echo -e "No\nYes" | dmenu -i -p "$1") \ +== "Yes" ] && $2 diff --git a/stuff/manual-programs/suckless/dwm/shiftview.c b/stuff/manual-programs/suckless/dwm/shiftview.c new file mode 100644 index 0000000..e82053a --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/shiftview.c @@ -0,0 +1,19 @@ +/** 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/stuff/manual-programs/suckless/dwm/transient.c b/stuff/manual-programs/suckless/dwm/transient.c new file mode 100644 index 0000000..040adb5 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/transient.c @@ -0,0 +1,42 @@ +/* cc transient.c -o transient -lX11 */ + +#include +#include +#include +#include + +int main(void) { + Display *d; + Window r, f, t = None; + XSizeHints h; + XEvent e; + + d = XOpenDisplay(NULL); + if (!d) + exit(1); + r = DefaultRootWindow(d); + + f = XCreateSimpleWindow(d, r, 100, 100, 400, 400, 0, 0, 0); + h.min_width = h.max_width = h.min_height = h.max_height = 400; + h.flags = PMinSize | PMaxSize; + XSetWMNormalHints(d, f, &h); + XStoreName(d, f, "floating"); + XMapWindow(d, f); + + XSelectInput(d, f, ExposureMask); + while (1) { + XNextEvent(d, &e); + + if (t == None) { + sleep(5); + t = XCreateSimpleWindow(d, r, 50, 50, 100, 100, 0, 0, 0); + XSetTransientForHint(d, t, f); + XStoreName(d, t, "transient"); + XMapWindow(d, t); + XSelectInput(d, t, ExposureMask); + } + } + + XCloseDisplay(d); + exit(0); +} diff --git a/stuff/manual-programs/suckless/dwm/util.c b/stuff/manual-programs/suckless/dwm/util.c new file mode 100644 index 0000000..fe044fc --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/util.c @@ -0,0 +1,35 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include + +#include "util.h" + +void * +ecalloc(size_t nmemb, size_t size) +{ + void *p; + + if (!(p = calloc(nmemb, size))) + die("calloc:"); + return p; +} + +void +die(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + if (fmt[0] && fmt[strlen(fmt)-1] == ':') { + fputc(' ', stderr); + perror(NULL); + } else { + fputc('\n', stderr); + } + + exit(1); +} diff --git a/stuff/manual-programs/suckless/dwm/util.h b/stuff/manual-programs/suckless/dwm/util.h new file mode 100644 index 0000000..f633b51 --- /dev/null +++ b/stuff/manual-programs/suckless/dwm/util.h @@ -0,0 +1,8 @@ +/* See LICENSE file for copyright and license details. */ + +#define MAX(A, B) ((A) > (B) ? (A) : (B)) +#define MIN(A, B) ((A) < (B) ? (A) : (B)) +#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B)) + +void die(const char *fmt, ...); +void *ecalloc(size_t nmemb, size_t size); diff --git a/stuff/manual-programs/suckless/dwm/util.o b/stuff/manual-programs/suckless/dwm/util.o new file mode 100644 index 0000000000000000000000000000000000000000..8e55fa18d6ada0bfba70d02362b40ffaf2d35ebf GIT binary patch literal 2224 zcmbtUO=uHQ5T0$TjWtbT?V(Z+5mrf{E}Ik~q$<%yyGoE+D{3#ACR-cKpPNldRWM>b zgb?V#qX!Qj6g(94C^YE7t4B}Pqfig^ASe~$%?e!*H_wR z+#gQLxBTIhT=s{b%5|js!_VYZOTUnxTl%%UX6d(b+tTmkPpGq6v+rmK4Gjy1B5kdC z3LW&mXss1_iv>os)~p=RT1i>`n3Mw^gi#NxEFAoX2Gl1&Yn~v>9Mc*b)Ud}2Xic>0 z4|+TC>cRCO#w|3`vDD_k`T&R4>1-_YvYq&(UG-`$t0N1T`;bZJ^QBB2U}|zQ9t=%g zx*85f#+9fN2}afExEfO#KRRyF-kt7tqjojnaLGz| z^@i91Tmi-r6@7;rexwT?>Vhj>aGJVXeVmikC-2WXC&VVY@S$qv@=6Aj)T9d8oDLN; zs~ZL^EtHL1(Of{^$m>N|C|Au4lrdB?K(FOY(Cv$XbxEqW!nxab;7`YvR}81SuooA{ z-!RcV5AE=@9h6{5Yy=>Xttsx zm@~xAiN_o+jADS!FTn{+*XXcOJS<^9+GN`A)BaCT{20R-oghnQoEtIR36CL8HUBlA z{(V$4ic1u}Kkt{v`2JicFhDl_*hQIR1pY7NF`mcu1q^VTb4V|_fiBz|h|xO}?<%@b zWBJa$oZoX7xkPp5zhwE-R7? +© 2009 Thomas Menari +© 2009 Simon Rozet +© 2009 Andrew Antle +© 2010-2011 pancake +© 2011-2013 Anselm R Garbe +© 2011-2012 Troels Henriksen +© 2011 Connor Lane Smith +© 2012-2017 Christoph Lohmann <20h@r-36.net> +© 2013 Shayan Pooya +© 2013 Jens Nyberg +© 2013 Carlos J. Torres +© 2013 Alexander Sedov +© 2013 Nick White +© 2013 David Dufberg +© 2014-2021 Quentin Rameau +© 2014-2016 Markus Teich +© 2015 Jakukyo Friel +© 2015 Ben Woolley +© 2015 Greg Reagle +© 2015 GhostAV +© 2015-2017 Ivan Tham +© 2015 Alexander Huemer +© 2015 Michael Stevens +© 2015 Felix Janda +© 2016 Charles Lehner +© 2016 Dmitry Bogatov +© 2017 Hiltjo Posthuma +© 2017 ssd +© 2017 Constantine Bytensky +© 2017 Eon S. Jeon +© 2017 Jochen Sprickerhof +© 2018 nzl +© 2018 Eddie Thieda +© 2018 Leonardo Taccari +© 2019 efe + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + diff --git a/stuff/manual-programs/suckless/surf/Makefile b/stuff/manual-programs/suckless/surf/Makefile new file mode 100644 index 0000000..1edf820 --- /dev/null +++ b/stuff/manual-programs/suckless/surf/Makefile @@ -0,0 +1,76 @@ +# surf - simple browser +# See LICENSE file for copyright and license details. +.POSIX: + +include config.mk + +SRC = surf.c +WSRC = webext-surf.c +OBJ = $(SRC:.c=.o) +WOBJ = $(WSRC:.c=.o) +WLIB = $(WSRC:.c=.so) + +all: options surf $(WLIB) + +options: + @echo surf build options: + @echo "CC = $(CC)" + @echo "CFLAGS = $(SURFCFLAGS) $(CFLAGS)" + @echo "WEBEXTCFLAGS = $(WEBEXTCFLAGS) $(CFLAGS)" + @echo "LDFLAGS = $(LDFLAGS)" + +surf: $(OBJ) + $(CC) $(SURFLDFLAGS) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) + +$(OBJ) $(WOBJ): config.h common.h config.mk + +config.h: + cp config.def.h $@ + +$(OBJ): $(SRC) + $(CC) $(SURFCFLAGS) $(CFLAGS) -c $(SRC) + +$(WLIB): $(WOBJ) + $(CC) -shared -Wl,-soname,$@ $(LDFLAGS) -o $@ $? $(WEBEXTLIBS) + +$(WOBJ): $(WSRC) + $(CC) $(WEBEXTCFLAGS) $(CFLAGS) -c $(WSRC) + +clean: + rm -f surf $(OBJ) + rm -f $(WLIB) $(WOBJ) + +distclean: clean + rm -f config.h surf-$(VERSION).tar.gz + +dist: distclean + mkdir -p surf-$(VERSION) + cp -R LICENSE Makefile config.mk config.def.h README \ + surf-open.sh arg.h TODO.md surf.png \ + surf.1 common.h $(SRC) $(WSRC) surf-$(VERSION) + tar -cf surf-$(VERSION).tar surf-$(VERSION) + gzip surf-$(VERSION).tar + rm -rf surf-$(VERSION) + +install: all + mkdir -p $(DESTDIR)$(PREFIX)/bin + cp -f surf $(DESTDIR)$(PREFIX)/bin + chmod 755 $(DESTDIR)$(PREFIX)/bin/surf + mkdir -p $(DESTDIR)$(LIBDIR) + cp -f $(WLIB) $(DESTDIR)$(LIBDIR) + for wlib in $(WLIB); do \ + chmod 644 $(DESTDIR)$(LIBDIR)/$$wlib; \ + done + mkdir -p $(DESTDIR)$(MANPREFIX)/man1 + sed "s/VERSION/$(VERSION)/g" < surf.1 > $(DESTDIR)$(MANPREFIX)/man1/surf.1 + chmod 644 $(DESTDIR)$(MANPREFIX)/man1/surf.1 + +uninstall: + rm -f $(DESTDIR)$(PREFIX)/bin/surf + rm -f $(DESTDIR)$(MANPREFIX)/man1/surf.1 + for wlib in $(WLIB); do \ + rm -f $(DESTDIR)$(LIBDIR)/$$wlib; \ + done + - rmdir $(DESTDIR)$(LIBDIR) + +.PHONY: all options distclean clean dist install uninstall diff --git a/stuff/manual-programs/suckless/surf/README b/stuff/manual-programs/suckless/surf/README new file mode 100644 index 0000000..da4577f --- /dev/null +++ b/stuff/manual-programs/suckless/surf/README @@ -0,0 +1,40 @@ +surf - simple webkit-based browser +================================== +surf is a simple Web browser based on WebKit/GTK+. + +Requirements +------------ +In order to build surf you need GTK+ and Webkit/GTK+ header files. + +In order to use the functionality of the url-bar, also install dmenu[0]. + +Installation +------------ +Edit config.mk to match your local setup (surf is installed into +the /usr/local namespace by default). + +Afterwards enter the following command to build and install surf (if +necessary as root): + + make clean install + +Running surf +------------ +run + surf [URI] + +See the manpage for further options. + +Running surf in tabbed +---------------------- +For running surf in tabbed[1] there is a script included in the distribution, +which is run like this: + + surf-open.sh [URI] + +Further invocations of the script will run surf with the specified URI in this +instance of tabbed. + +[0] http://tools.suckless.org/dmenu +[1] http://tools.suckless.org/tabbed + diff --git a/stuff/manual-programs/suckless/surf/TODO.md b/stuff/manual-programs/suckless/surf/TODO.md new file mode 100644 index 0000000..da5f44d --- /dev/null +++ b/stuff/manual-programs/suckless/surf/TODO.md @@ -0,0 +1,10 @@ +# TODO + +* suckless adblocking +* replace twitch() with proper gtk calls to make scrollbars reappear +* replace webkit with something sane +* add video player options + * play in plugin + * play in video player + * call command with URI (quvi + cclive) + diff --git a/stuff/manual-programs/suckless/surf/arg.h b/stuff/manual-programs/suckless/surf/arg.h new file mode 100644 index 0000000..ba3fb3f --- /dev/null +++ b/stuff/manual-programs/suckless/surf/arg.h @@ -0,0 +1,48 @@ +/* + * Copy me if you can. + * by 20h + */ + +#ifndef ARG_H__ +#define ARG_H__ + +extern char *argv0; + +/* use main(int argc, char *argv[]) */ +#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ + argv[0] && argv[0][0] == '-'\ + && argv[0][1];\ + argc--, argv++) {\ + char argc_;\ + char **argv_;\ + int brk_;\ + if (argv[0][1] == '-' && argv[0][2] == '\0') {\ + argv++;\ + argc--;\ + break;\ + }\ + for (brk_ = 0, argv[0]++, argv_ = argv;\ + argv[0][0] && !brk_;\ + argv[0]++) {\ + if (argv_ != argv)\ + break;\ + argc_ = argv[0][0];\ + switch (argc_) +#define ARGEND }\ + } + +#define ARGC() argc_ + +#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\ + ((x), abort(), (char *)0) :\ + (brk_ = 1, (argv[0][1] != '\0')?\ + (&argv[0][1]) :\ + (argc--, argv++, argv[0]))) + +#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\ + (char *)0 :\ + (brk_ = 1, (argv[0][1] != '\0')?\ + (&argv[0][1]) :\ + (argc--, argv++, argv[0]))) + +#endif diff --git a/stuff/manual-programs/suckless/surf/common.h b/stuff/manual-programs/suckless/surf/common.h new file mode 100644 index 0000000..3990c42 --- /dev/null +++ b/stuff/manual-programs/suckless/surf/common.h @@ -0,0 +1 @@ +#define MSGBUFSZ 8 diff --git a/stuff/manual-programs/suckless/surf/config.def.h b/stuff/manual-programs/suckless/surf/config.def.h new file mode 100644 index 0000000..4744f37 --- /dev/null +++ b/stuff/manual-programs/suckless/surf/config.def.h @@ -0,0 +1,205 @@ +/* modifier 0 means no modifier */ +static int surfuseragent = 1; /* Append Surf version to default WebKit user agent */ +static char *fulluseragent = ""; /* Or override the whole user agent string */ +static char *scriptfile = "~/.surf/script.js"; +static char *styledir = "~/.surf/styles/"; +static char *certdir = "~/.surf/certificates/"; +static char *cachedir = "~/.surf/cache/"; +static char *cookiefile = "~/.surf/cookies.txt"; + +/* Webkit default features */ +/* Highest priority value will be used. + * Default parameters are priority 0 + * Per-uri parameters are priority 1 + * Command parameters are priority 2 + */ +static Parameter defconfig[ParameterLast] = { + /* parameter Arg value priority */ + [AccessMicrophone] = { { .i = 0 }, }, + [AccessWebcam] = { { .i = 0 }, }, + [Certificate] = { { .i = 0 }, }, + [CaretBrowsing] = { { .i = 0 }, }, + [CookiePolicies] = { { .v = "@Aa" }, }, + [DarkMode] = { { .i = 0 }, }, + [DefaultCharset] = { { .v = "UTF-8" }, }, + [DiskCache] = { { .i = 1 }, }, + [DNSPrefetch] = { { .i = 0 }, }, + [Ephemeral] = { { .i = 0 }, }, + [FileURLsCrossAccess] = { { .i = 0 }, }, + [FontSize] = { { .i = 12 }, }, + [Geolocation] = { { .i = 0 }, }, + [HideBackground] = { { .i = 0 }, }, + [Inspector] = { { .i = 1 }, }, + [JavaScript] = { { .i = 1 }, }, + [KioskMode] = { { .i = 0 }, }, + [LoadImages] = { { .i = 1 }, }, + [MediaManualPlay] = { { .i = 1 }, }, + [PreferredLanguages] = { { .v = (char *[]){ NULL } }, }, + [RunInFullscreen] = { { .i = 0 }, }, + [ScrollBars] = { { .i = 1 }, }, + [ShowIndicators] = { { .i = 1 }, }, + [SiteQuirks] = { { .i = 1 }, }, + [SmoothScrolling] = { { .i = 0 }, }, + [SpellChecking] = { { .i = 0 }, }, + [SpellLanguages] = { { .v = ((char *[]){ "en_US", NULL }) }, }, + [StrictTLS] = { { .i = 1 }, }, + [Style] = { { .i = 1 }, }, + [WebGL] = { { .i = 0 }, }, + [ZoomLevel] = { { .f = 1.0 }, }, +}; + +static UriParameters uriparams[] = { + { "(://|\\.)suckless\\.org(/|$)", { + [JavaScript] = { { .i = 0 }, 1 }, + }, }, +}; + +/* default window size: width, height */ +static int winsize[] = { 800, 600 }; + +static WebKitFindOptions findopts = WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE | + WEBKIT_FIND_OPTIONS_WRAP_AROUND; + +#define PROMPT_GO "Go:" +#define PROMPT_FIND "Find:" + +/* SETPROP(readprop, setprop, prompt)*/ +#define SETPROP(r, s, p) { \ + .v = (const char *[]){ "/bin/sh", "-c", \ + "prop=\"$(printf '%b' \"$(xprop -id $1 "r" " \ + "| sed -e 's/^"r"(UTF8_STRING) = \"\\(.*\\)\"/\\1/' " \ + " -e 's/\\\\\\(.\\)/\\1/g')\" " \ + "| dmenu -p '"p"' -w $1)\" " \ + "&& xprop -id $1 -f "s" 8u -set "s" \"$prop\"", \ + "surf-setprop", winid, NULL \ + } \ +} + +/* DOWNLOAD(URI, referer) */ +#define DOWNLOAD(u, r) { \ + .v = (const char *[]){ "st", "-e", "/bin/sh", "-c",\ + "curl -g -L -J -O -A \"$1\" -b \"$2\" -c \"$2\"" \ + " -e \"$3\" \"$4\"; read", \ + "surf-download", useragent, cookiefile, r, u, NULL \ + } \ +} + +/* PLUMB(URI) */ +/* This called when some URI which does not begin with "about:", + * "http://" or "https://" should be opened. + */ +#define PLUMB(u) {\ + .v = (const char *[]){ "/bin/sh", "-c", \ + "xdg-open \"$0\"", u, NULL \ + } \ +} + +/* VIDEOPLAY(URI) */ +#define VIDEOPLAY(u) {\ + .v = (const char *[]){ "/bin/sh", "-c", \ + "mpv --really-quiet \"$0\"", u, NULL \ + } \ +} + +/* styles */ +/* + * The iteration will stop at the first match, beginning at the beginning of + * the list. + */ +static SiteSpecific styles[] = { + /* regexp file in $styledir */ + { ".*", "default.css" }, +}; + +/* certificates */ +/* + * Provide custom certificate for urls + */ +static SiteSpecific certs[] = { + /* regexp file in $certdir */ + { "://suckless\\.org/", "suckless.org.crt" }, +}; + +#define MODKEY GDK_CONTROL_MASK + +/* hotkeys */ +/* + * If you use anything else but MODKEY and GDK_SHIFT_MASK, don't forget to + * edit the CLEANMASK() macro. + */ +static Key keys[] = { + /* modifier keyval function arg */ + { 0, GDK_KEY_g, spawn, SETPROP("_SURF_URI", "_SURF_GO", PROMPT_GO) }, + { 0, GDK_KEY_f, spawn, SETPROP("_SURF_FIND", "_SURF_FIND", PROMPT_FIND) }, + { 0, GDK_KEY_slash, spawn, SETPROP("_SURF_FIND", "_SURF_FIND", PROMPT_FIND) }, + + { 0, GDK_KEY_i, insert, { .i = 1 } }, + { 0, GDK_KEY_Escape, insert, { .i = 0 } }, + + { 0, GDK_KEY_c, stop, { 0 } }, + + { MODKEY, GDK_KEY_r, reload, { .i = 1 } }, + { 0, GDK_KEY_r, reload, { .i = 0 } }, + + { 0, GDK_KEY_l, navigate, { .i = +1 } }, + { 0, GDK_KEY_h, navigate, { .i = -1 } }, + + /* vertical and horizontal scrolling, in viewport percentage */ + { 0, GDK_KEY_j, scrollv, { .i = +10 } }, + { 0, GDK_KEY_k, scrollv, { .i = -10 } }, + { 0, GDK_KEY_space, scrollv, { .i = +50 } }, + { 0, GDK_KEY_b, scrollv, { .i = -50 } }, + { 0, GDK_KEY_i, scrollh, { .i = +10 } }, + { 0, GDK_KEY_u, scrollh, { .i = -10 } }, + + + { 0|GDK_SHIFT_MASK, GDK_KEY_j, zoom, { .i = -1 } }, + { 0|GDK_SHIFT_MASK, GDK_KEY_k, zoom, { .i = +1 } }, + { 0|GDK_SHIFT_MASK, GDK_KEY_q, zoom, { .i = 0 } }, + { 0, GDK_KEY_minus, zoom, { .i = -1 } }, + { 0|GDK_SHIFT_MASK, GDK_KEY_plus, zoom, { .i = +1 } }, + { 0, GDK_KEY_equal, zoom, { .i = 0 } }, + + { 0, GDK_KEY_p, clipboard, { .i = 1 } }, + { 0, GDK_KEY_y, clipboard, { .i = 0 } }, + + { 0, GDK_KEY_n, find, { .i = +1 } }, + { 0|GDK_SHIFT_MASK, GDK_KEY_n, find, { .i = -1 } }, + + { MODKEY, GDK_KEY_p, print, { 0 } }, + { MODKEY, GDK_KEY_t, showcert, { 0 } }, + + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_a, togglecookiepolicy, { 0 } }, + { 0, GDK_KEY_F11, togglefullscreen, { 0 } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_o, toggleinspector, { 0 } }, + + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_c, toggle, { .i = CaretBrowsing } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_g, toggle, { .i = Geolocation } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_s, toggle, { .i = JavaScript } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_i, toggle, { .i = LoadImages } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_b, toggle, { .i = ScrollBars } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_t, toggle, { .i = StrictTLS } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_m, toggle, { .i = Style } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_d, toggle, { .i = DarkMode } }, +}; + +/* button definitions */ +/* target can be OnDoc, OnLink, OnImg, OnMedia, OnEdit, OnBar, OnSel, OnAny */ +static Button buttons[] = { + /* target event mask button function argument stop event */ + { OnLink, 0, 2, clicknewwindow, { .i = 0 }, 1 }, + { OnLink, MODKEY, 2, clicknewwindow, { .i = 1 }, 1 }, + { OnLink, MODKEY, 1, clicknewwindow, { .i = 1 }, 1 }, + { OnAny, 0, 8, clicknavigate, { .i = -1 }, 1 }, + { OnAny, 0, 9, clicknavigate, { .i = +1 }, 1 }, + { OnMedia, MODKEY, 1, clickexternplayer, { 0 }, 1 }, +}; + +/* Put here your aliases */ +static Alias aliases[] = { + /* Alias URI */ + { "ddg", "https://duckduckgo.com" }, + { "brave", "https://search.brave.com" }, + { "searx", "https://search.bus-hit.me" }, + { "wiki", "https://www.wikipedia.org" } +}; diff --git a/stuff/manual-programs/suckless/surf/config.def.h.orig b/stuff/manual-programs/suckless/surf/config.def.h.orig new file mode 100644 index 0000000..e340bab --- /dev/null +++ b/stuff/manual-programs/suckless/surf/config.def.h.orig @@ -0,0 +1,200 @@ +/* modifier 0 means no modifier */ +static int surfuseragent = 1; /* Append Surf version to default WebKit user agent */ +static char *fulluseragent = ""; /* Or override the whole user agent string */ +static char *scriptfile = "~/.surf/script.js"; +static char *styledir = "~/.surf/styles/"; +static char *certdir = "~/.surf/certificates/"; +static char *cachedir = "~/.surf/cache/"; +static char *cookiefile = "~/.surf/cookies.txt"; + +/* Webkit default features */ +/* Highest priority value will be used. + * Default parameters are priority 0 + * Per-uri parameters are priority 1 + * Command parameters are priority 2 + */ +static Parameter defconfig[ParameterLast] = { + /* parameter Arg value priority */ + [AccessMicrophone] = { { .i = 0 }, }, + [AccessWebcam] = { { .i = 0 }, }, + [Certificate] = { { .i = 0 }, }, + [CaretBrowsing] = { { .i = 0 }, }, + [CookiePolicies] = { { .v = "@Aa" }, }, + [DarkMode] = { { .i = 0 }, }, + [DefaultCharset] = { { .v = "UTF-8" }, }, + [DiskCache] = { { .i = 1 }, }, + [DNSPrefetch] = { { .i = 0 }, }, + [Ephemeral] = { { .i = 0 }, }, + [FileURLsCrossAccess] = { { .i = 0 }, }, + [FontSize] = { { .i = 12 }, }, + [Geolocation] = { { .i = 0 }, }, + [HideBackground] = { { .i = 0 }, }, + [Inspector] = { { .i = 0 }, }, + [JavaScript] = { { .i = 1 }, }, + [KioskMode] = { { .i = 0 }, }, + [LoadImages] = { { .i = 1 }, }, + [MediaManualPlay] = { { .i = 1 }, }, + [PreferredLanguages] = { { .v = (char *[]){ NULL } }, }, + [RunInFullscreen] = { { .i = 0 }, }, + [ScrollBars] = { { .i = 1 }, }, + [ShowIndicators] = { { .i = 1 }, }, + [SiteQuirks] = { { .i = 1 }, }, + [SmoothScrolling] = { { .i = 0 }, }, + [SpellChecking] = { { .i = 0 }, }, + [SpellLanguages] = { { .v = ((char *[]){ "en_US", NULL }) }, }, + [StrictTLS] = { { .i = 1 }, }, + [Style] = { { .i = 1 }, }, + [WebGL] = { { .i = 0 }, }, + [ZoomLevel] = { { .f = 1.0 }, }, +}; + +static UriParameters uriparams[] = { + { "(://|\\.)suckless\\.org(/|$)", { + [JavaScript] = { { .i = 0 }, 1 }, + }, }, +}; + +/* default window size: width, height */ +static int winsize[] = { 800, 600 }; + +static WebKitFindOptions findopts = WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE | + WEBKIT_FIND_OPTIONS_WRAP_AROUND; + +#define PROMPT_GO "Go:" +#define PROMPT_FIND "Find:" + +/* SETPROP(readprop, setprop, prompt)*/ +#define SETPROP(r, s, p) { \ + .v = (const char *[]){ "/bin/sh", "-c", \ + "prop=\"$(printf '%b' \"$(xprop -id $1 "r" " \ + "| sed -e 's/^"r"(UTF8_STRING) = \"\\(.*\\)\"/\\1/' " \ + " -e 's/\\\\\\(.\\)/\\1/g')\" " \ + "| dmenu -p '"p"' -w $1)\" " \ + "&& xprop -id $1 -f "s" 8u -set "s" \"$prop\"", \ + "surf-setprop", winid, NULL \ + } \ +} + +/* DOWNLOAD(URI, referer) */ +#define DOWNLOAD(u, r) { \ + .v = (const char *[]){ "st", "-e", "/bin/sh", "-c",\ + "curl -g -L -J -O -A \"$1\" -b \"$2\" -c \"$2\"" \ + " -e \"$3\" \"$4\"; read", \ + "surf-download", useragent, cookiefile, r, u, NULL \ + } \ +} + +/* PLUMB(URI) */ +/* This called when some URI which does not begin with "about:", + * "http://" or "https://" should be opened. + */ +#define PLUMB(u) {\ + .v = (const char *[]){ "/bin/sh", "-c", \ + "xdg-open \"$0\"", u, NULL \ + } \ +} + +/* VIDEOPLAY(URI) */ +#define VIDEOPLAY(u) {\ + .v = (const char *[]){ "/bin/sh", "-c", \ + "mpv --really-quiet \"$0\"", u, NULL \ + } \ +} + +/* styles */ +/* + * The iteration will stop at the first match, beginning at the beginning of + * the list. + */ +static SiteSpecific styles[] = { + /* regexp file in $styledir */ + { ".*", "default.css" }, +}; + +/* certificates */ +/* + * Provide custom certificate for urls + */ +static SiteSpecific certs[] = { + /* regexp file in $certdir */ + { "://suckless\\.org/", "suckless.org.crt" }, +}; + +#define MODKEY GDK_CONTROL_MASK + +/* hotkeys */ +/* + * If you use anything else but MODKEY and GDK_SHIFT_MASK, don't forget to + * edit the CLEANMASK() macro. + */ +static Key keys[] = { + /* modifier keyval function arg */ + { MODKEY, GDK_KEY_g, spawn, SETPROP("_SURF_URI", "_SURF_GO", PROMPT_GO) }, + { MODKEY, GDK_KEY_f, spawn, SETPROP("_SURF_FIND", "_SURF_FIND", PROMPT_FIND) }, + { MODKEY, GDK_KEY_slash, spawn, SETPROP("_SURF_FIND", "_SURF_FIND", PROMPT_FIND) }, + + { 0, GDK_KEY_Escape, stop, { 0 } }, + { MODKEY, GDK_KEY_c, stop, { 0 } }, + + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_r, reload, { .i = 1 } }, + { MODKEY, GDK_KEY_r, reload, { .i = 0 } }, + + { MODKEY, GDK_KEY_l, navigate, { .i = +1 } }, + { MODKEY, GDK_KEY_h, navigate, { .i = -1 } }, + + /* vertical and horizontal scrolling, in viewport percentage */ + { MODKEY, GDK_KEY_j, scrollv, { .i = +10 } }, + { MODKEY, GDK_KEY_k, scrollv, { .i = -10 } }, + { MODKEY, GDK_KEY_space, scrollv, { .i = +50 } }, + { MODKEY, GDK_KEY_b, scrollv, { .i = -50 } }, + { MODKEY, GDK_KEY_i, scrollh, { .i = +10 } }, + { MODKEY, GDK_KEY_u, scrollh, { .i = -10 } }, + + + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_j, zoom, { .i = -1 } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_k, zoom, { .i = +1 } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_q, zoom, { .i = 0 } }, + { MODKEY, GDK_KEY_minus, zoom, { .i = -1 } }, + { MODKEY, GDK_KEY_plus, zoom, { .i = +1 } }, + + { MODKEY, GDK_KEY_p, clipboard, { .i = 1 } }, + { MODKEY, GDK_KEY_y, clipboard, { .i = 0 } }, + + { MODKEY, GDK_KEY_n, find, { .i = +1 } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_n, find, { .i = -1 } }, + + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_p, print, { 0 } }, + { MODKEY, GDK_KEY_t, showcert, { 0 } }, + + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_a, togglecookiepolicy, { 0 } }, + { 0, GDK_KEY_F11, togglefullscreen, { 0 } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_o, toggleinspector, { 0 } }, + + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_c, toggle, { .i = CaretBrowsing } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_g, toggle, { .i = Geolocation } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_s, toggle, { .i = JavaScript } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_i, toggle, { .i = LoadImages } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_b, toggle, { .i = ScrollBars } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_t, toggle, { .i = StrictTLS } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_m, toggle, { .i = Style } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_d, toggle, { .i = DarkMode } }, +}; + +/* button definitions */ +/* target can be OnDoc, OnLink, OnImg, OnMedia, OnEdit, OnBar, OnSel, OnAny */ +static Button buttons[] = { + /* target event mask button function argument stop event */ + { OnLink, 0, 2, clicknewwindow, { .i = 0 }, 1 }, + { OnLink, MODKEY, 2, clicknewwindow, { .i = 1 }, 1 }, + { OnLink, MODKEY, 1, clicknewwindow, { .i = 1 }, 1 }, + { OnAny, 0, 8, clicknavigate, { .i = -1 }, 1 }, + { OnAny, 0, 9, clicknavigate, { .i = +1 }, 1 }, + { OnMedia, MODKEY, 1, clickexternplayer, { 0 }, 1 }, +}; + +/* Put here your aliases */ +static Alias aliases[] = { + /* Alias URI */ + { "ddg", "https://duckduckgo.com" }, + { "wiki", "https://www.wikipedia.org" } +}; diff --git a/stuff/manual-programs/suckless/surf/config.h b/stuff/manual-programs/suckless/surf/config.h new file mode 100644 index 0000000..9cbd06b --- /dev/null +++ b/stuff/manual-programs/suckless/surf/config.h @@ -0,0 +1,205 @@ +/* modifier 0 means no modifier */ +static int surfuseragent = 1; /* Append Surf version to default WebKit user agent */ +static char *fulluseragent = ""; /* Or override the whole user agent string */ +static char *scriptfile = "~/.surf/script.js"; +static char *styledir = "~/.surf/styles/"; +static char *certdir = "~/.surf/certificates/"; +static char *cachedir = "~/.surf/cache/"; +static char *cookiefile = "~/.surf/cookies.txt"; + +/* Webkit default features */ +/* Highest priority value will be used. + * Default parameters are priority 0 + * Per-uri parameters are priority 1 + * Command parameters are priority 2 + */ +static Parameter defconfig[ParameterLast] = { + /* parameter Arg value priority */ + [AccessMicrophone] = { { .i = 0 }, }, + [AccessWebcam] = { { .i = 0 }, }, + [Certificate] = { { .i = 0 }, }, + [CaretBrowsing] = { { .i = 0 }, }, + [CookiePolicies] = { { .v = "@Aa" }, }, + [DarkMode] = { { .i = 0 }, }, + [DefaultCharset] = { { .v = "UTF-8" }, }, + [DiskCache] = { { .i = 1 }, }, + [DNSPrefetch] = { { .i = 0 }, }, + [Ephemeral] = { { .i = 0 }, }, + [FileURLsCrossAccess] = { { .i = 0 }, }, + [FontSize] = { { .i = 12 }, }, + [Geolocation] = { { .i = 0 }, }, + [HideBackground] = { { .i = 0 }, }, + [Inspector] = { { .i = 1 }, }, + [JavaScript] = { { .i = 1 }, }, + [KioskMode] = { { .i = 0 }, }, + [LoadImages] = { { .i = 1 }, }, + [MediaManualPlay] = { { .i = 1 }, }, + [PreferredLanguages] = { { .v = (char *[]){ NULL } }, }, + [RunInFullscreen] = { { .i = 0 }, }, + [ScrollBars] = { { .i = 1 }, }, + [ShowIndicators] = { { .i = 1 }, }, + [SiteQuirks] = { { .i = 1 }, }, + [SmoothScrolling] = { { .i = 0 }, }, + [SpellChecking] = { { .i = 0 }, }, + [SpellLanguages] = { { .v = ((char *[]){ "en_US", NULL }) }, }, + [StrictTLS] = { { .i = 1 }, }, + [Style] = { { .i = 1 }, }, + [WebGL] = { { .i = 0 }, }, + [ZoomLevel] = { { .f = 1.0 }, }, +}; + +static UriParameters uriparams[] = { + { "(://|\\.)suckless\\.org(/|$)", { + [JavaScript] = { { .i = 0 }, 1 }, + }, }, +}; + +/* default window size: width, height */ +static int winsize[] = { 800, 600 }; + +static WebKitFindOptions findopts = WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE | + WEBKIT_FIND_OPTIONS_WRAP_AROUND; + +#define PROMPT_GO "Go:" +#define PROMPT_FIND "Find:" + +/* SETPROP(readprop, setprop, prompt)*/ +#define SETPROP(r, s, p) { \ + .v = (const char *[]){ "/bin/sh", "-c", \ + "prop=\"$(printf '%b' \"$(xprop -id $1 "r" " \ + "| sed -e 's/^"r"(UTF8_STRING) = \"\\(.*\\)\"/\\1/' " \ + " -e 's/\\\\\\(.\\)/\\1/g')\" " \ + "| rofi -dmenu -p '"p"' -w $1)\" " \ + "&& xprop -id $1 -f "s" 8u -set "s" \"$prop\"", \ + "surf-setprop", winid, NULL \ + } \ +} + +/* DOWNLOAD(URI, referer) */ +#define DOWNLOAD(u, r) { \ + .v = (const char *[]){ "st", "-e", "/bin/sh", "-c",\ + "curl -g -L -J -O -A \"$1\" -b \"$2\" -c \"$2\"" \ + " -e \"$3\" \"$4\"; read", \ + "surf-download", useragent, cookiefile, r, u, NULL \ + } \ +} + +/* PLUMB(URI) */ +/* This called when some URI which does not begin with "about:", + * "http://" or "https://" should be opened. + */ +#define PLUMB(u) {\ + .v = (const char *[]){ "/bin/sh", "-c", \ + "xdg-open \"$0\"", u, NULL \ + } \ +} + +/* VIDEOPLAY(URI) */ +#define VIDEOPLAY(u) {\ + .v = (const char *[]){ "/bin/sh", "-c", \ + "mpv --really-quiet \"$0\"", u, NULL \ + } \ +} + +/* styles */ +/* + * The iteration will stop at the first match, beginning at the beginning of + * the list. + */ +static SiteSpecific styles[] = { + /* regexp file in $styledir */ + { ".*", "default.css" }, +}; + +/* certificates */ +/* + * Provide custom certificate for urls + */ +static SiteSpecific certs[] = { + /* regexp file in $certdir */ + { "://suckless\\.org/", "suckless.org.crt" }, +}; + +#define MODKEY GDK_CONTROL_MASK + +/* hotkeys */ +/* + * If you use anything else but MODKEY and GDK_SHIFT_MASK, don't forget to + * edit the CLEANMASK() macro. + */ +static Key keys[] = { + /* modifier keyval function arg */ + { 0, GDK_KEY_g, spawn, SETPROP("_SURF_URI", "_SURF_GO", PROMPT_GO) }, + { 0, GDK_KEY_f, spawn, SETPROP("_SURF_FIND", "_SURF_FIND", PROMPT_FIND) }, + { 0, GDK_KEY_slash, spawn, SETPROP("_SURF_FIND", "_SURF_FIND", PROMPT_FIND) }, + + { 0, GDK_KEY_i, insert, { .i = 1 } }, + { 0, GDK_KEY_Escape, insert, { .i = 0 } }, + + { 0, GDK_KEY_c, stop, { 0 } }, + + { MODKEY, GDK_KEY_r, reload, { .i = 1 } }, + { 0, GDK_KEY_r, reload, { .i = 0 } }, + + { 0, GDK_KEY_l, navigate, { .i = +1 } }, + { 0, GDK_KEY_h, navigate, { .i = -1 } }, + + /* vertical and horizontal scrolling, in viewport percentage */ + { 0, GDK_KEY_j, scrollv, { .i = +10 } }, + { 0, GDK_KEY_k, scrollv, { .i = -10 } }, + { 0, GDK_KEY_space, scrollv, { .i = +50 } }, + { 0, GDK_KEY_b, scrollv, { .i = -50 } }, + { 0, GDK_KEY_i, scrollh, { .i = +10 } }, + { 0, GDK_KEY_u, scrollh, { .i = -10 } }, + + + { 0|GDK_SHIFT_MASK, GDK_KEY_j, zoom, { .i = -1 } }, + { 0|GDK_SHIFT_MASK, GDK_KEY_k, zoom, { .i = +1 } }, + { 0|GDK_SHIFT_MASK, GDK_KEY_q, zoom, { .i = 0 } }, + { 0, GDK_KEY_minus, zoom, { .i = -1 } }, + { 0|GDK_SHIFT_MASK, GDK_KEY_plus, zoom, { .i = +1 } }, + { 0, GDK_KEY_equal, zoom, { .i = 0 } }, + + { 0, GDK_KEY_p, clipboard, { .i = 1 } }, + { 0, GDK_KEY_y, clipboard, { .i = 0 } }, + + { 0, GDK_KEY_n, find, { .i = +1 } }, + { 0|GDK_SHIFT_MASK, GDK_KEY_n, find, { .i = -1 } }, + + { MODKEY, GDK_KEY_p, print, { 0 } }, + { MODKEY, GDK_KEY_t, showcert, { 0 } }, + + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_a, togglecookiepolicy, { 0 } }, + { 0, GDK_KEY_F11, togglefullscreen, { 0 } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_o, toggleinspector, { 0 } }, + + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_c, toggle, { .i = CaretBrowsing } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_g, toggle, { .i = Geolocation } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_s, toggle, { .i = JavaScript } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_i, toggle, { .i = LoadImages } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_b, toggle, { .i = ScrollBars } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_t, toggle, { .i = StrictTLS } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_m, toggle, { .i = Style } }, + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_d, toggle, { .i = DarkMode } }, +}; + +/* button definitions */ +/* target can be OnDoc, OnLink, OnImg, OnMedia, OnEdit, OnBar, OnSel, OnAny */ +static Button buttons[] = { + /* target event mask button function argument stop event */ + { OnLink, 0, 2, clicknewwindow, { .i = 0 }, 1 }, + { OnLink, MODKEY, 2, clicknewwindow, { .i = 1 }, 1 }, + { OnLink, MODKEY, 1, clicknewwindow, { .i = 1 }, 1 }, + { OnAny, 0, 8, clicknavigate, { .i = -1 }, 1 }, + { OnAny, 0, 9, clicknavigate, { .i = +1 }, 1 }, + { OnMedia, MODKEY, 1, clickexternplayer, { 0 }, 1 }, +}; + +/* Put here your aliases */ +static Alias aliases[] = { + /* Alias URI */ + { "ddg", "https://duckduckgo.com" }, + { "brave", "https://search.brave.com" }, + { "searx", "https://search.bus-hit.me" }, + { "wiki", "https://www.wikipedia.org" } +}; diff --git a/stuff/manual-programs/suckless/surf/config.mk b/stuff/manual-programs/suckless/surf/config.mk new file mode 100644 index 0000000..2eb9fb0 --- /dev/null +++ b/stuff/manual-programs/suckless/surf/config.mk @@ -0,0 +1,32 @@ +# surf version +VERSION = 2.1 + +# Customize below to fit your system + +# paths +PREFIX = /usr/local +MANPREFIX = $(PREFIX)/share/man +LIBPREFIX = $(PREFIX)/lib +LIBDIR = $(LIBPREFIX)/surf + +X11INC = `pkg-config --cflags x11` +X11LIB = `pkg-config --libs x11` + +GTKINC = `pkg-config --cflags gtk+-3.0 gcr-3 webkit2gtk-4.0` +GTKLIB = `pkg-config --libs gtk+-3.0 gcr-3 webkit2gtk-4.0` +WEBEXTINC = `pkg-config --cflags webkit2gtk-4.0 webkit2gtk-web-extension-4.0 gio-2.0` +WEBEXTLIBS = `pkg-config --libs webkit2gtk-4.0 webkit2gtk-web-extension-4.0 gio-2.0` + +# includes and libs +INCS = $(X11INC) $(GTKINC) +LIBS = $(X11LIB) $(GTKLIB) -lgthread-2.0 + +# flags +CPPFLAGS = -DVERSION=\"$(VERSION)\" -DGCR_API_SUBJECT_TO_CHANGE \ + -DLIBPREFIX=\"$(LIBPREFIX)\" -DWEBEXTDIR=\"$(LIBDIR)\" \ + -D_DEFAULT_SOURCE +SURFCFLAGS = -fPIC $(INCS) $(CPPFLAGS) +WEBEXTCFLAGS = -fPIC $(WEBEXTINC) + +# compiler +#CC = c99 diff --git a/stuff/manual-programs/suckless/surf/surf b/stuff/manual-programs/suckless/surf/surf new file mode 100644 index 0000000000000000000000000000000000000000..4774188a36925db45d159f1fddf2ad3f6e700ec5 GIT binary patch literal 75024 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 z%0D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 +Date: Sat, 9 Feb 2019 13:16:51 -0500 +Subject: [PATCH] Modal behaviour, 'i' to insert 'Esc' to get to the normal + mode + +--- + config.def.h | 53 +++++++++++++++++++++++++++------------------------- + surf.c | 14 +++++++++++++- + 2 files changed, 41 insertions(+), 26 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 34265f6..8b7d5a2 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -130,41 +130,44 @@ static SiteSpecific certs[] = { + */ + static Key keys[] = { + /* modifier keyval function arg */ +- { MODKEY, GDK_KEY_g, spawn, SETPROP("_SURF_URI", "_SURF_GO", PROMPT_GO) }, +- { MODKEY, GDK_KEY_f, spawn, SETPROP("_SURF_FIND", "_SURF_FIND", PROMPT_FIND) }, +- { MODKEY, GDK_KEY_slash, spawn, SETPROP("_SURF_FIND", "_SURF_FIND", PROMPT_FIND) }, ++ { 0, GDK_KEY_g, spawn, SETPROP("_SURF_URI", "_SURF_GO", PROMPT_GO) }, ++ { 0, GDK_KEY_f, spawn, SETPROP("_SURF_FIND", "_SURF_FIND", PROMPT_FIND) }, ++ { 0, GDK_KEY_slash, spawn, SETPROP("_SURF_FIND", "_SURF_FIND", PROMPT_FIND) }, + +- { 0, GDK_KEY_Escape, stop, { 0 } }, +- { MODKEY, GDK_KEY_c, stop, { 0 } }, ++ { 0, GDK_KEY_i, insert, { .i = 1 } }, ++ { 0, GDK_KEY_Escape, insert, { .i = 0 } }, + +- { MODKEY|GDK_SHIFT_MASK, GDK_KEY_r, reload, { .i = 1 } }, +- { MODKEY, GDK_KEY_r, reload, { .i = 0 } }, ++ { 0, GDK_KEY_c, stop, { 0 } }, + +- { MODKEY, GDK_KEY_l, navigate, { .i = +1 } }, +- { MODKEY, GDK_KEY_h, navigate, { .i = -1 } }, ++ { MODKEY, GDK_KEY_r, reload, { .i = 1 } }, ++ { 0, GDK_KEY_r, reload, { .i = 0 } }, ++ ++ { 0, GDK_KEY_l, navigate, { .i = +1 } }, ++ { 0, GDK_KEY_h, navigate, { .i = -1 } }, + + /* vertical and horizontal scrolling, in viewport percentage */ +- { MODKEY, GDK_KEY_j, scrollv, { .i = +10 } }, +- { MODKEY, GDK_KEY_k, scrollv, { .i = -10 } }, +- { MODKEY, GDK_KEY_space, scrollv, { .i = +50 } }, +- { MODKEY, GDK_KEY_b, scrollv, { .i = -50 } }, +- { MODKEY, GDK_KEY_i, scrollh, { .i = +10 } }, +- { MODKEY, GDK_KEY_u, scrollh, { .i = -10 } }, ++ { 0, GDK_KEY_j, scrollv, { .i = +10 } }, ++ { 0, GDK_KEY_k, scrollv, { .i = -10 } }, ++ { 0, GDK_KEY_space, scrollv, { .i = +50 } }, ++ { 0, GDK_KEY_b, scrollv, { .i = -50 } }, ++ { 0, GDK_KEY_i, scrollh, { .i = +10 } }, ++ { 0, GDK_KEY_u, scrollh, { .i = -10 } }, + + +- { MODKEY|GDK_SHIFT_MASK, GDK_KEY_j, zoom, { .i = -1 } }, +- { MODKEY|GDK_SHIFT_MASK, GDK_KEY_k, zoom, { .i = +1 } }, +- { MODKEY|GDK_SHIFT_MASK, GDK_KEY_q, zoom, { .i = 0 } }, +- { MODKEY, GDK_KEY_minus, zoom, { .i = -1 } }, +- { MODKEY, GDK_KEY_plus, zoom, { .i = +1 } }, ++ { 0|GDK_SHIFT_MASK, GDK_KEY_j, zoom, { .i = -1 } }, ++ { 0|GDK_SHIFT_MASK, GDK_KEY_k, zoom, { .i = +1 } }, ++ { 0|GDK_SHIFT_MASK, GDK_KEY_q, zoom, { .i = 0 } }, ++ { 0, GDK_KEY_minus, zoom, { .i = -1 } }, ++ { 0|GDK_SHIFT_MASK, GDK_KEY_plus, zoom, { .i = +1 } }, ++ { 0, GDK_KEY_equal, zoom, { .i = 0 } }, + +- { MODKEY, GDK_KEY_p, clipboard, { .i = 1 } }, +- { MODKEY, GDK_KEY_y, clipboard, { .i = 0 } }, ++ { 0, GDK_KEY_p, clipboard, { .i = 1 } }, ++ { 0, GDK_KEY_y, clipboard, { .i = 0 } }, + +- { MODKEY, GDK_KEY_n, find, { .i = +1 } }, +- { MODKEY|GDK_SHIFT_MASK, GDK_KEY_n, find, { .i = -1 } }, ++ { 0, GDK_KEY_n, find, { .i = +1 } }, ++ { 0|GDK_SHIFT_MASK, GDK_KEY_n, find, { .i = -1 } }, + +- { MODKEY|GDK_SHIFT_MASK, GDK_KEY_p, print, { 0 } }, ++ { MODKEY, GDK_KEY_p, print, { 0 } }, + { MODKEY, GDK_KEY_t, showcert, { 0 } }, + + { MODKEY|GDK_SHIFT_MASK, GDK_KEY_a, togglecookiepolicy, { 0 } }, +diff --git a/surf.c b/surf.c +index 2b54e3c..f4cbe68 100644 +--- a/surf.c ++++ b/surf.c +@@ -175,6 +175,7 @@ static void spawn(Client *c, const Arg *a); + static void msgext(Client *c, char type, const Arg *a); + static void destroyclient(Client *c); + static void cleanup(void); ++static int insertmode = 0; + + /* GTK/WebKit */ + static WebKitWebView *newview(Client *c, WebKitWebView *rv); +@@ -231,6 +232,7 @@ static void togglefullscreen(Client *c, const Arg *a); + static void togglecookiepolicy(Client *c, const Arg *a); + static void toggleinspector(Client *c, const Arg *a); + static void find(Client *c, const Arg *a); ++static void insert(Client *c, const Arg *a); + + /* Buttons */ + static void clicknavigate(Client *c, const Arg *a, WebKitHitTestResult *h); +@@ -1333,7 +1335,11 @@ winevent(GtkWidget *w, GdkEvent *e, Client *c) + updatetitle(c); + break; + case GDK_KEY_PRESS: +- if (!curconfig[KioskMode].val.i) { ++ if (!curconfig[KioskMode].val.i && ++ !insertmode || ++ CLEANMASK(e->key.state) == (MODKEY|GDK_SHIFT_MASK) || ++ CLEANMASK(e->key.state) == (MODKEY) || ++ gdk_keyval_to_lower(e->key.keyval) == (GDK_KEY_Escape)) { + for (i = 0; i < LENGTH(keys); ++i) { + if (gdk_keyval_to_lower(e->key.keyval) == + keys[i].keyval && +@@ -1947,6 +1953,12 @@ find(Client *c, const Arg *a) + } + } + ++void ++insert(Client *c, const Arg *a) ++{ ++ insertmode = (a->i); ++} ++ + void + clicknavigate(Client *c, const Arg *a, WebKitHitTestResult *h) + { +-- +2.20.1 + diff --git a/stuff/manual-programs/suckless/surf/surf-open.sh b/stuff/manual-programs/suckless/surf/surf-open.sh new file mode 100644 index 0000000..c22edc2 --- /dev/null +++ b/stuff/manual-programs/suckless/surf/surf-open.sh @@ -0,0 +1,32 @@ +#!/bin/sh +# +# See the LICENSE file for copyright and license details. +# + +xidfile="$HOME/tmp/tabbed-surf.xid" +uri="" + +if [ "$#" -gt 0 ]; +then + uri="$1" +fi + +runtabbed() { + tabbed -dn tabbed-surf -r 2 surf -e '' "$uri" >"$xidfile" \ + 2>/dev/null & +} + +if [ ! -r "$xidfile" ]; +then + runtabbed +else + xid=$(cat "$xidfile") + xprop -id "$xid" >/dev/null 2>&1 + if [ $? -gt 0 ]; + then + runtabbed + else + surf -e "$xid" "$uri" >/dev/null 2>&1 & + fi +fi + diff --git a/stuff/manual-programs/suckless/surf/surf-uri-aliases-20220930-089272b.diff b/stuff/manual-programs/suckless/surf/surf-uri-aliases-20220930-089272b.diff new file mode 100644 index 0000000..98ed58d --- /dev/null +++ b/stuff/manual-programs/suckless/surf/surf-uri-aliases-20220930-089272b.diff @@ -0,0 +1,58 @@ +From 089272be1459bc91800215d39f483a2584ae99cc Mon Sep 17 00:00:00 2001 +From: r4v10l1 <29655971+r4v10l1@users.noreply.github.com> +Date: Fri, 30 Sep 2022 18:59:15 +0200 +Subject: [PATCH] Alias patch + +--- + config.def.h | 7 +++++++ + surf.c | 12 ++++++++++++ + 2 files changed, 19 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 93cfeeb..2b19183 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -194,3 +194,10 @@ static Button buttons[] = { + { OnAny, 0, 9, clicknavigate, { .i = +1 }, 1 }, + { OnMedia, MODKEY, 1, clickexternplayer, { 0 }, 1 }, + }; ++ ++/* Put here your aliases */ ++static Alias aliases[] = { ++ /* Alias URI */ ++ { "ddg", "https://duckduckgo.com" }, ++ { "wikipedia", "https://www.wikipedia.org" } ++}; +diff --git a/surf.c b/surf.c +index 474c01b..25f8528 100644 +--- a/surf.c ++++ b/surf.c +@@ -144,6 +144,11 @@ typedef struct { + regex_t re; + } SiteSpecific; + ++typedef struct { ++ const char* alias; ++ const char* uri; ++} Alias; ++ + /* Surf */ + static void die(const char *errstr, ...); + static void usage(void); +@@ -567,6 +572,13 @@ loaduri(Client *c, const Arg *a) + if (g_strcmp0(uri, "") == 0) + return; + ++ for (int i = 0; i < LENGTH(aliases); i++) { ++ if (strcmp(aliases[i].alias, uri) == 0) { ++ uri = aliases[i].uri; ++ break; ++ } ++ } ++ + if (g_str_has_prefix(uri, "http://") || + g_str_has_prefix(uri, "https://") || + g_str_has_prefix(uri, "file://") || +-- +2.37.3 + diff --git a/stuff/manual-programs/suckless/surf/surf.1 b/stuff/manual-programs/suckless/surf/surf.1 new file mode 100644 index 0000000..23117b1 --- /dev/null +++ b/stuff/manual-programs/suckless/surf/surf.1 @@ -0,0 +1,305 @@ +.TH SURF 1 surf\-VERSION +.SH NAME +surf \- simple webkit-based browser +.SH SYNOPSIS +.B surf +.RB [-bBdDfFgGiIkKmMnNpPsStTvwxX] +.RB [-a\ cookiepolicies] +.RB [-c\ cookiefile] +.RB [-C\ stylefile] +.RB [-e\ xid] +.RB [-r\ scriptfile] +.RB [-u\ useragent] +.RB [-z\ zoomlevel] +.RB [URI] +.SH DESCRIPTION +surf is a simple Web browser based on WebKit/GTK+. It is able +to display websites and follow links. It supports the XEmbed protocol +which makes it possible to embed it in another application. Furthermore, +one can point surf to another URI by setting its XProperties. +.SH OPTIONS +.TP +.B \-a cookiepolicies +Define the order of +.I cookie policies\fR. +The default is "@Aa" but could be +redefined in the +.IR config.h , +with "A" meaning to +accept all cookies, "a" to deny all cookies and "@", which tells surf to +accept no third party cookies. +.TP +.B \-b +Disable Scrollbars. +.TP +.B \-B +Enable Scrollbars. +.TP +.B \-c cookiefile +Specify the +.I cookiefile +to use. +.TP +.B \-C stylefile +Specify the user +.IR stylefile . +This does disable the site-specific styles. +.TP +.B \-d +Disable the disk cache. +.TP +.B \-D +Enable the disk cache. +.TP +.B \-e xid +Reparents to window specified by +.IR xid . +.TP +.B \-f +Start surf in windowed mode (not fullscreen). +.TP +.B \-F +Start surf in fullscreen mode. +.TP +.B \-g +Disable giving the geolocation to websites. +.TP +.B \-G +Enable giving the geolocation to websites. +.TP +.B \-i +Disable Images. +.TP +.B \-I +Enable Images. +.TP +.B \-k +Disable kiosk mode (disable key strokes and right click). +.TP +.B \-K +Enable kiosk mode (disable key strokes and right click). +.TP +.B \-m +Disable application of user style sheets. +.TP +.B \-M +Enable application of user style sheets. +.TP +.B \-n +Disable the Web Inspector (Developer Tools). +.TP +.B \-N +Enable the Web Inspector (Developer Tools). +.TP +.B \-r scriptfile +Specify the user +.IR scriptfile . +.TP +.B \-s +Disable Javascript. +.TP +.B \-S +Enable Javascript. +.TP +.B \-t +Disable strict TLS check. +.TP +.B \-T +Enable strict TLS check. +.TP +.B \-u useragent +Specify the +.I useragent +which surf should use. +.TP +.B \-v +Prints version information to standard output, then exits. +.TP +.B \-w +Prints xid to standard output. This can be used to script the browser in for +example +.BR xdotool(1) . +.TP +.B -x +Disable custom certificates. +.TP +.B -X +Enable custom certificates. +.TP +.B \-z zoomlevel +Specify the +.I zoomlevel +which surf should use. +.SH USAGE +.B Escape +Stops loading current page or stops download. +.TP +.B Ctrl\-h +Walks back the history. +.TP +.B Ctrl\-l +Walks forward the history. +.TP +.B Ctrl\-k +Scrolls page upwards. +.TP +.B Ctrl\-j +Scrolls page downwards. +.TP +.B Ctrl\-b +Scroll up one whole page view. +.TP +.B Ctrl\-Space +Scroll down one whole page view. +.TP +.B Ctrl\-i +Scroll horizontally to the right. +.TP +.B Ctrl\-u +Scroll horizontally to the left. +.TP +.B Ctrl\-Shift\-k or Ctrl\-+ +Zooms page in. +.TP +.B Ctrl\-Shift\-j or Ctrl\-- +Zooms page out. +.TP +.B Ctrl\-Shift\-q +Resets Zoom. +.TP +.B Ctrl\-f and Ctrl\-/ +Opens the search-bar. +.TP +.B Ctrl\-n +Go to next search result. +.TP +.B Ctrl\-Shift\-n +Go to previous search result. +.TP +.B Ctrl\-g +Opens the URL-bar (requires dmenu installed). +.TP +.B Ctrl\-p +Loads URI from primary selection. +.TP +.B Ctrl\-Shift\-p +Calls Printpage Dialog. +.TP +.B Ctrl\-r +Reloads the website. +.TP +.B Ctrl\-Shift\-r +Reloads the website without using the cache. +.TP +.B Ctrl\-y +Copies current URI to primary selection. +.TP +.B Ctrl\-t +Display the current TLS certificate in a popup window. +.TP +.B Ctrl\-Shift\-a +Toggle through the the +.I cookie policies\fR. +This will not reload the page. +.TP +.B Ctrl\-Shift\-b +Toggle scrollbars. This will reload the page. +.TP +.B Ctrl\-Shift\-c +Toggle caret browsing. This will reload the page. +.TP +.B Ctrl\-Shift\-d +Toggle dark mode. +.TP +.B Ctrl\-Shift\-i +Toggle auto-loading of images. This will reload the page. +.TP +.B Ctrl\-Shift\-m +Toggle if the +.I stylefile +file should be loaded. This will reload the page. +.TP +.B Ctrl\-Shift\-o +Open the Web Inspector (Developer Tools) window for the current page. +.TP +.B Ctrl\-Shift\-s +Toggle script execution. This will reload the page. +.TP +.B Ctrl\-Shift\-t +Toggle strict TLS check. This will reload the page. +.TP +.B F11 +Toggle fullscreen mode. +.SH INDICATORS OF OPERATION +Surf is showing indicators of operation in front of the site title. +For all indicators, unless otherwise specified, a lower case letter means disabled and an upper case letter means enabled. +.TP +.B A +all cookies accepted +.TP +.B a +no cookies accepted +.TP +.B @ +all except third-party cookies accepted +.TP +.B c C +caret browsing +.TP +.B g G +geolocation +.TP +.B d D +disk cache +.TP +.B i I +images +.TP +.B s S +scripts +.TP +.B m M +styles +.TP +.B x X +custom certificates +.TP +.B t T +strict TLS +.SH INDICATORS OF WEB PAGE +The second part of the indicators specifies modes of the web page itself. +.SS First character: encryption +.TP +.B - +unencrypted +.TP +.B T +encrypted (TLS) +.TP +.B U +attempted encryption but failed +.SS Second character: proxying +.TP +.B - +no proxy +.TP +.B P +using proxy +.SH ENVIRONMENT +.B SURF_USERAGENT +If this variable is set upon startup, surf will use it as the +.I useragent +string. +.TP +.B http_proxy +If this variable is set and not empty upon startup, surf will use it as the http proxy. +.SH SIGNALS +Surf will reload the current page on +.BR SIGHUP . +.SH SEE ALSO +.BR dmenu(1), +.BR xprop(1), +.BR tabbed(1), +.BR xdotool(1) +.SH BUGS +Please report them! diff --git a/stuff/manual-programs/suckless/surf/surf.c b/stuff/manual-programs/suckless/surf/surf.c new file mode 100644 index 0000000..ecb9ab4 --- /dev/null +++ b/stuff/manual-programs/suckless/surf/surf.c @@ -0,0 +1,2155 @@ +/* See LICENSE file for copyright and license details. + * + * To understand surf, start reading main(). + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "arg.h" +#include "common.h" + +#define LENGTH(x) (sizeof(x) / sizeof(x[0])) +#define CLEANMASK(mask) (mask & (MODKEY|GDK_SHIFT_MASK)) + +enum { AtomFind, AtomGo, AtomUri, AtomUTF8, AtomLast }; + +enum { + OnDoc = WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT, + OnLink = WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK, + OnImg = WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE, + OnMedia = WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA, + OnEdit = WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE, + OnBar = WEBKIT_HIT_TEST_RESULT_CONTEXT_SCROLLBAR, + OnSel = WEBKIT_HIT_TEST_RESULT_CONTEXT_SELECTION, + OnAny = OnDoc | OnLink | OnImg | OnMedia | OnEdit | OnBar | OnSel, +}; + +typedef enum { + AccessMicrophone, + AccessWebcam, + CaretBrowsing, + Certificate, + CookiePolicies, + DarkMode, + DiskCache, + DefaultCharset, + DNSPrefetch, + Ephemeral, + FileURLsCrossAccess, + FontSize, + Geolocation, + HideBackground, + Inspector, + JavaScript, + KioskMode, + LoadImages, + MediaManualPlay, + PreferredLanguages, + RunInFullscreen, + ScrollBars, + ShowIndicators, + SiteQuirks, + SmoothScrolling, + SpellChecking, + SpellLanguages, + StrictTLS, + Style, + WebGL, + ZoomLevel, + ParameterLast +} ParamName; + +typedef union { + int i; + float f; + const void *v; +} Arg; + +typedef struct { + Arg val; + int prio; +} Parameter; + +typedef struct Client { + GtkWidget *win; + WebKitWebView *view; + WebKitSettings *settings; + WebKitWebContext *context; + WebKitWebInspector *inspector; + WebKitFindController *finder; + WebKitHitTestResult *mousepos; + GTlsCertificate *cert, *failedcert; + GTlsCertificateFlags tlserr; + Window xid; + guint64 pageid; + int progress, fullscreen, https, insecure, errorpage; + const char *title, *overtitle, *targeturi; + const char *needle; + struct Client *next; +} Client; + +typedef struct { + guint mod; + guint keyval; + void (*func)(Client *c, const Arg *a); + const Arg arg; +} Key; + +typedef struct { + unsigned int target; + unsigned int mask; + guint button; + void (*func)(Client *c, const Arg *a, WebKitHitTestResult *h); + const Arg arg; + unsigned int stopevent; +} Button; + +typedef struct { + const char *uri; + Parameter config[ParameterLast]; + regex_t re; +} UriParameters; + +typedef struct { + char *regex; + char *file; + regex_t re; +} SiteSpecific; + +typedef struct { + const char* alias; + const char* uri; +} Alias; + +/* Surf */ +static void die(const char *errstr, ...); +static void usage(void); +static void setup(void); +static void sigchld(int unused); +static void sighup(int unused); +static char *buildfile(const char *path); +static char *buildpath(const char *path); +static char *untildepath(const char *path); +static const char *getuserhomedir(const char *user); +static const char *getcurrentuserhomedir(void); +static Client *newclient(Client *c); +static void loaduri(Client *c, const Arg *a); +static const char *geturi(Client *c); +static void setatom(Client *c, int a, const char *v); +static const char *getatom(Client *c, int a); +static void updatetitle(Client *c); +static void gettogglestats(Client *c); +static void getpagestats(Client *c); +static WebKitCookieAcceptPolicy cookiepolicy_get(void); +static char cookiepolicy_set(const WebKitCookieAcceptPolicy p); +static void seturiparameters(Client *c, const char *uri, ParamName *params); +static void setparameter(Client *c, int refresh, ParamName p, const Arg *a); +static const char *getcert(const char *uri); +static void setcert(Client *c, const char *file); +static const char *getstyle(const char *uri); +static void setstyle(Client *c, const char *file); +static void runscript(Client *c); +static void evalscript(Client *c, const char *jsstr, ...); +static void updatewinid(Client *c); +static void handleplumb(Client *c, const char *uri); +static void newwindow(Client *c, const Arg *a, int noembed); +static void spawn(Client *c, const Arg *a); +static void msgext(Client *c, char type, const Arg *a); +static void destroyclient(Client *c); +static void cleanup(void); +static int insertmode = 0; + +/* GTK/WebKit */ +static WebKitWebView *newview(Client *c, WebKitWebView *rv); +static void initwebextensions(WebKitWebContext *wc, Client *c); +static GtkWidget *createview(WebKitWebView *v, WebKitNavigationAction *a, + Client *c); +static gboolean buttonreleased(GtkWidget *w, GdkEvent *e, Client *c); +static GdkFilterReturn processx(GdkXEvent *xevent, GdkEvent *event, + gpointer d); +static gboolean winevent(GtkWidget *w, GdkEvent *e, Client *c); +static void showview(WebKitWebView *v, Client *c); +static GtkWidget *createwindow(Client *c); +static gboolean loadfailedtls(WebKitWebView *v, gchar *uri, + GTlsCertificate *cert, + GTlsCertificateFlags err, Client *c); +static void loadchanged(WebKitWebView *v, WebKitLoadEvent e, Client *c); +static void progresschanged(WebKitWebView *v, GParamSpec *ps, Client *c); +static void titlechanged(WebKitWebView *view, GParamSpec *ps, Client *c); +static void mousetargetchanged(WebKitWebView *v, WebKitHitTestResult *h, + guint modifiers, Client *c); +static gboolean permissionrequested(WebKitWebView *v, + WebKitPermissionRequest *r, Client *c); +static gboolean decidepolicy(WebKitWebView *v, WebKitPolicyDecision *d, + WebKitPolicyDecisionType dt, Client *c); +static void decidenavigation(WebKitPolicyDecision *d, Client *c); +static void decidenewwindow(WebKitPolicyDecision *d, Client *c); +static void decideresource(WebKitPolicyDecision *d, Client *c); +static void insecurecontent(WebKitWebView *v, WebKitInsecureContentEvent e, + Client *c); +static void downloadstarted(WebKitWebContext *wc, WebKitDownload *d, + Client *c); +static void responsereceived(WebKitDownload *d, GParamSpec *ps, Client *c); +static void download(Client *c, WebKitURIResponse *r); +static gboolean viewusrmsgrcv(WebKitWebView *v, WebKitUserMessage *m, + gpointer u); +static void webprocessterminated(WebKitWebView *v, + WebKitWebProcessTerminationReason r, + Client *c); +static void closeview(WebKitWebView *v, Client *c); +static void destroywin(GtkWidget* w, Client *c); + +/* Hotkeys */ +static void pasteuri(GtkClipboard *clipboard, const char *text, gpointer d); +static void reload(Client *c, const Arg *a); +static void print(Client *c, const Arg *a); +static void showcert(Client *c, const Arg *a); +static void clipboard(Client *c, const Arg *a); +static void zoom(Client *c, const Arg *a); +static void scrollv(Client *c, const Arg *a); +static void scrollh(Client *c, const Arg *a); +static void navigate(Client *c, const Arg *a); +static void stop(Client *c, const Arg *a); +static void toggle(Client *c, const Arg *a); +static void togglefullscreen(Client *c, const Arg *a); +static void togglecookiepolicy(Client *c, const Arg *a); +static void toggleinspector(Client *c, const Arg *a); +static void find(Client *c, const Arg *a); +static void insert(Client *c, const Arg *a); + +/* Buttons */ +static void clicknavigate(Client *c, const Arg *a, WebKitHitTestResult *h); +static void clicknewwindow(Client *c, const Arg *a, WebKitHitTestResult *h); +static void clickexternplayer(Client *c, const Arg *a, WebKitHitTestResult *h); + +static char winid[64]; +static char togglestats[11]; +static char pagestats[2]; +static Atom atoms[AtomLast]; +static Window embed; +static int showxid; +static int cookiepolicy; +static Display *dpy; +static Client *clients; +static GdkDevice *gdkkb; +static char *stylefile; +static const char *useragent; +static Parameter *curconfig; +static int modparams[ParameterLast]; +static int spair[2]; +char *argv0; + +static ParamName loadtransient[] = { + Certificate, + CookiePolicies, + DiskCache, + DNSPrefetch, + FileURLsCrossAccess, + JavaScript, + LoadImages, + PreferredLanguages, + ShowIndicators, + StrictTLS, + ParameterLast +}; + +static ParamName loadcommitted[] = { +// AccessMicrophone, +// AccessWebcam, + CaretBrowsing, + DarkMode, + DefaultCharset, + FontSize, + Geolocation, + HideBackground, + Inspector, +// KioskMode, + MediaManualPlay, + RunInFullscreen, + ScrollBars, + SiteQuirks, + SmoothScrolling, + SpellChecking, + SpellLanguages, + Style, + ZoomLevel, + ParameterLast +}; + +static ParamName loadfinished[] = { + ParameterLast +}; + +/* configuration, allows nested code to access above variables */ +#include "config.h" + +void +die(const char *errstr, ...) +{ + va_list ap; + + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + exit(1); +} + +void +usage(void) +{ + die("usage: surf [-bBdDfFgGiIkKmMnNsStTvwxX]\n" + "[-a cookiepolicies ] [-c cookiefile] [-C stylefile] [-e xid]\n" + "[-r scriptfile] [-u useragent] [-z zoomlevel] [uri]\n"); +} + +void +setup(void) +{ + GIOChannel *gchanin; + GdkDisplay *gdpy; + int i, j; + + /* clean up any zombies immediately */ + sigchld(0); + if (signal(SIGHUP, sighup) == SIG_ERR) + die("Can't install SIGHUP handler"); + + if (!(dpy = XOpenDisplay(NULL))) + die("Can't open default display"); + + /* atoms */ + atoms[AtomFind] = XInternAtom(dpy, "_SURF_FIND", False); + atoms[AtomGo] = XInternAtom(dpy, "_SURF_GO", False); + atoms[AtomUri] = XInternAtom(dpy, "_SURF_URI", False); + atoms[AtomUTF8] = XInternAtom(dpy, "UTF8_STRING", False); + + gtk_init(NULL, NULL); + + gdpy = gdk_display_get_default(); + + curconfig = defconfig; + + /* dirs and files */ + cookiefile = buildfile(cookiefile); + scriptfile = buildfile(scriptfile); + certdir = buildpath(certdir); + if (curconfig[Ephemeral].val.i) + cachedir = NULL; + else + cachedir = buildpath(cachedir); + + gdkkb = gdk_seat_get_keyboard(gdk_display_get_default_seat(gdpy)); + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, spair) < 0) { + fputs("Unable to create sockets\n", stderr); + spair[0] = spair[1] = -1; + } else { + gchanin = g_io_channel_unix_new(spair[0]); + g_io_channel_set_encoding(gchanin, NULL, NULL); + g_io_channel_set_flags(gchanin, g_io_channel_get_flags(gchanin) + | G_IO_FLAG_NONBLOCK, NULL); + g_io_channel_set_close_on_unref(gchanin, TRUE); + } + + + for (i = 0; i < LENGTH(certs); ++i) { + if (!regcomp(&(certs[i].re), certs[i].regex, REG_EXTENDED)) { + certs[i].file = g_strconcat(certdir, "/", certs[i].file, + NULL); + } else { + fprintf(stderr, "Could not compile regex: %s\n", + certs[i].regex); + certs[i].regex = NULL; + } + } + + if (!stylefile) { + styledir = buildpath(styledir); + for (i = 0; i < LENGTH(styles); ++i) { + if (!regcomp(&(styles[i].re), styles[i].regex, + REG_EXTENDED)) { + styles[i].file = g_strconcat(styledir, "/", + styles[i].file, NULL); + } else { + fprintf(stderr, "Could not compile regex: %s\n", + styles[i].regex); + styles[i].regex = NULL; + } + } + g_free(styledir); + } else { + stylefile = buildfile(stylefile); + } + + for (i = 0; i < LENGTH(uriparams); ++i) { + if (regcomp(&(uriparams[i].re), uriparams[i].uri, + REG_EXTENDED)) { + fprintf(stderr, "Could not compile regex: %s\n", + uriparams[i].uri); + uriparams[i].uri = NULL; + continue; + } + + /* copy default parameters with higher priority */ + for (j = 0; j < ParameterLast; ++j) { + if (defconfig[j].prio >= uriparams[i].config[j].prio) + uriparams[i].config[j] = defconfig[j]; + } + } +} + +void +sigchld(int unused) +{ + if (signal(SIGCHLD, sigchld) == SIG_ERR) + die("Can't install SIGCHLD handler"); + while (waitpid(-1, NULL, WNOHANG) > 0) + ; +} + +void +sighup(int unused) +{ + Arg a = { .i = 0 }; + Client *c; + + for (c = clients; c; c = c->next) + reload(c, &a); +} + +char * +buildfile(const char *path) +{ + char *dname, *bname, *bpath, *fpath; + FILE *f; + + dname = g_path_get_dirname(path); + bname = g_path_get_basename(path); + + bpath = buildpath(dname); + g_free(dname); + + fpath = g_build_filename(bpath, bname, NULL); + g_free(bpath); + g_free(bname); + + if (!(f = fopen(fpath, "a"))) + die("Could not open file: %s\n", fpath); + + g_chmod(fpath, 0600); /* always */ + fclose(f); + + return fpath; +} + +static const char* +getuserhomedir(const char *user) +{ + struct passwd *pw = getpwnam(user); + + if (!pw) + die("Can't get user %s login information.\n", user); + + return pw->pw_dir; +} + +static const char* +getcurrentuserhomedir(void) +{ + const char *homedir; + const char *user; + struct passwd *pw; + + homedir = getenv("HOME"); + if (homedir) + return homedir; + + user = getenv("USER"); + if (user) + return getuserhomedir(user); + + pw = getpwuid(getuid()); + if (!pw) + die("Can't get current user home directory\n"); + + return pw->pw_dir; +} + +char * +buildpath(const char *path) +{ + char *apath, *fpath; + + if (path[0] == '~') + apath = untildepath(path); + else + apath = g_strdup(path); + + /* creating directory */ + if (g_mkdir_with_parents(apath, 0700) < 0) + die("Could not access directory: %s\n", apath); + + fpath = realpath(apath, NULL); + g_free(apath); + + return fpath; +} + +char * +untildepath(const char *path) +{ + char *apath, *name, *p; + const char *homedir; + + if (path[1] == '/' || path[1] == '\0') { + p = (char *)&path[1]; + homedir = getcurrentuserhomedir(); + } else { + if ((p = strchr(path, '/'))) + name = g_strndup(&path[1], p - (path + 1)); + else + name = g_strdup(&path[1]); + + homedir = getuserhomedir(name); + g_free(name); + } + apath = g_build_filename(homedir, p, NULL); + return apath; +} + +Client * +newclient(Client *rc) +{ + Client *c; + + if (!(c = calloc(1, sizeof(Client)))) + die("Cannot malloc!\n"); + + c->next = clients; + clients = c; + + c->progress = 100; + c->view = newview(c, rc ? rc->view : NULL); + + return c; +} + +void +loaduri(Client *c, const Arg *a) +{ + struct stat st; + char *url, *path, *apath; + const char *uri = a->v; + + if (g_strcmp0(uri, "") == 0) + return; + + for (int i = 0; i < LENGTH(aliases); i++) { + if (strcmp(aliases[i].alias, uri) == 0) { + uri = aliases[i].uri; + break; + } + } + + if (g_str_has_prefix(uri, "http://") || + g_str_has_prefix(uri, "https://") || + g_str_has_prefix(uri, "file://") || + g_str_has_prefix(uri, "webkit://") || + g_str_has_prefix(uri, "about:")) { + url = g_strdup(uri); + } else { + if (uri[0] == '~') + apath = untildepath(uri); + else + apath = (char *)uri; + if (!stat(apath, &st) && (path = realpath(apath, NULL))) { + url = g_strdup_printf("file://%s", path); + free(path); + } else { + url = g_strdup_printf("http://%s", uri); + } + if (apath != uri) + free(apath); + } + + setatom(c, AtomUri, url); + + if (strcmp(url, geturi(c)) == 0) { + reload(c, a); + } else { + webkit_web_view_load_uri(c->view, url); + updatetitle(c); + } + + g_free(url); +} + +const char * +geturi(Client *c) +{ + const char *uri; + + if (!(uri = webkit_web_view_get_uri(c->view))) + uri = "about:blank"; + return uri; +} + +void +setatom(Client *c, int a, const char *v) +{ + XChangeProperty(dpy, c->xid, + atoms[a], atoms[AtomUTF8], 8, PropModeReplace, + (unsigned char *)v, strlen(v) + 1); + XSync(dpy, False); +} + +const char * +getatom(Client *c, int a) +{ + static char buf[BUFSIZ]; + Atom adummy; + int idummy; + unsigned long ldummy; + unsigned char *p = NULL; + + XSync(dpy, False); + XGetWindowProperty(dpy, c->xid, + atoms[a], 0L, BUFSIZ, False, atoms[AtomUTF8], + &adummy, &idummy, &ldummy, &ldummy, &p); + if (p) + strncpy(buf, (char *)p, LENGTH(buf) - 1); + else + buf[0] = '\0'; + XFree(p); + + return buf; +} + +void +updatetitle(Client *c) +{ + char *title; + const char *name = c->overtitle ? c->overtitle : + c->title ? c->title : ""; + + if (curconfig[ShowIndicators].val.i) { + gettogglestats(c); + getpagestats(c); + + if (c->progress != 100) + title = g_strdup_printf("[%i%%] %s:%s | %s", + c->progress, togglestats, pagestats, name); + else + title = g_strdup_printf("%s:%s | %s", + togglestats, pagestats, name); + + gtk_window_set_title(GTK_WINDOW(c->win), title); + g_free(title); + } else { + gtk_window_set_title(GTK_WINDOW(c->win), name); + } +} + +void +gettogglestats(Client *c) +{ + togglestats[0] = cookiepolicy_set(cookiepolicy_get()); + togglestats[1] = curconfig[CaretBrowsing].val.i ? 'C' : 'c'; + togglestats[2] = curconfig[Geolocation].val.i ? 'G' : 'g'; + togglestats[3] = curconfig[DiskCache].val.i ? 'D' : 'd'; + togglestats[4] = curconfig[LoadImages].val.i ? 'I' : 'i'; + togglestats[5] = curconfig[JavaScript].val.i ? 'S' : 's'; + togglestats[6] = curconfig[Style].val.i ? 'M' : 'm'; + togglestats[8] = curconfig[Certificate].val.i ? 'X' : 'x'; + togglestats[9] = curconfig[StrictTLS].val.i ? 'T' : 't'; +} + +void +getpagestats(Client *c) +{ + if (c->https) + pagestats[0] = (c->tlserr || c->insecure) ? 'U' : 'T'; + else + pagestats[0] = '-'; + pagestats[1] = '\0'; +} + +WebKitCookieAcceptPolicy +cookiepolicy_get(void) +{ + switch (((char *)curconfig[CookiePolicies].val.v)[cookiepolicy]) { + case 'a': + return WEBKIT_COOKIE_POLICY_ACCEPT_NEVER; + case '@': + return WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY; + default: /* fallthrough */ + case 'A': + return WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS; + } +} + +char +cookiepolicy_set(const WebKitCookieAcceptPolicy p) +{ + switch (p) { + case WEBKIT_COOKIE_POLICY_ACCEPT_NEVER: + return 'a'; + case WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY: + return '@'; + default: /* fallthrough */ + case WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS: + return 'A'; + } +} + +void +seturiparameters(Client *c, const char *uri, ParamName *params) +{ + Parameter *config, *uriconfig = NULL; + int i, p; + + for (i = 0; i < LENGTH(uriparams); ++i) { + if (uriparams[i].uri && + !regexec(&(uriparams[i].re), uri, 0, NULL, 0)) { + uriconfig = uriparams[i].config; + break; + } + } + + curconfig = uriconfig ? uriconfig : defconfig; + + for (i = 0; (p = params[i]) != ParameterLast; ++i) { + switch(p) { + default: /* FALLTHROUGH */ + if (!(defconfig[p].prio < curconfig[p].prio || + defconfig[p].prio < modparams[p])) + continue; + case Certificate: + case CookiePolicies: + case Style: + setparameter(c, 0, p, &curconfig[p].val); + } + } +} + +void +setparameter(Client *c, int refresh, ParamName p, const Arg *a) +{ + GdkRGBA bgcolor = { 0 }; + + modparams[p] = curconfig[p].prio; + + switch (p) { + case AccessMicrophone: + return; /* do nothing */ + case AccessWebcam: + return; /* do nothing */ + case CaretBrowsing: + webkit_settings_set_enable_caret_browsing(c->settings, a->i); + refresh = 0; + break; + case Certificate: + if (a->i) + setcert(c, geturi(c)); + return; /* do not update */ + case CookiePolicies: + webkit_cookie_manager_set_accept_policy( + webkit_web_context_get_cookie_manager(c->context), + cookiepolicy_get()); + refresh = 0; + break; + case DarkMode: + g_object_set(gtk_settings_get_default(), + "gtk-application-prefer-dark-theme", a->i, NULL); + return; + case DiskCache: + webkit_web_context_set_cache_model(c->context, a->i ? + WEBKIT_CACHE_MODEL_WEB_BROWSER : + WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER); + return; /* do not update */ + case DefaultCharset: + webkit_settings_set_default_charset(c->settings, a->v); + return; /* do not update */ + case DNSPrefetch: + webkit_settings_set_enable_dns_prefetching(c->settings, a->i); + return; /* do not update */ + case FileURLsCrossAccess: + webkit_settings_set_allow_file_access_from_file_urls( + c->settings, a->i); + webkit_settings_set_allow_universal_access_from_file_urls( + c->settings, a->i); + return; /* do not update */ + case FontSize: + webkit_settings_set_default_font_size(c->settings, a->i); + return; /* do not update */ + case Geolocation: + refresh = 0; + break; + case HideBackground: + if (a->i) + webkit_web_view_set_background_color(c->view, &bgcolor); + return; /* do not update */ + case Inspector: + webkit_settings_set_enable_developer_extras(c->settings, a->i); + return; /* do not update */ + case JavaScript: + webkit_settings_set_enable_javascript(c->settings, a->i); + break; + case KioskMode: + return; /* do nothing */ + case LoadImages: + webkit_settings_set_auto_load_images(c->settings, a->i); + break; + case MediaManualPlay: + webkit_settings_set_media_playback_requires_user_gesture( + c->settings, a->i); + break; + case PreferredLanguages: + return; /* do nothing */ + case RunInFullscreen: + return; /* do nothing */ + case ScrollBars: + /* Disabled until we write some WebKitWebExtension for + * manipulating the DOM directly. + enablescrollbars = !enablescrollbars; + evalscript(c, "document.documentElement.style.overflow = '%s'", + enablescrollbars ? "auto" : "hidden"); + */ + return; /* do not update */ + case ShowIndicators: + break; + case SmoothScrolling: + webkit_settings_set_enable_smooth_scrolling(c->settings, a->i); + return; /* do not update */ + case SiteQuirks: + webkit_settings_set_enable_site_specific_quirks( + c->settings, a->i); + break; + case SpellChecking: + webkit_web_context_set_spell_checking_enabled( + c->context, a->i); + return; /* do not update */ + case SpellLanguages: + return; /* do nothing */ + case StrictTLS: + webkit_website_data_manager_set_tls_errors_policy( + webkit_web_view_get_website_data_manager(c->view), a->i ? + WEBKIT_TLS_ERRORS_POLICY_FAIL : + WEBKIT_TLS_ERRORS_POLICY_IGNORE); + break; + case Style: + webkit_user_content_manager_remove_all_style_sheets( + webkit_web_view_get_user_content_manager(c->view)); + if (a->i) + setstyle(c, getstyle(geturi(c))); + refresh = 0; + break; + case WebGL: + webkit_settings_set_enable_webgl(c->settings, a->i); + break; + case ZoomLevel: + webkit_web_view_set_zoom_level(c->view, a->f); + return; /* do not update */ + default: + return; /* do nothing */ + } + + updatetitle(c); + if (refresh) + reload(c, a); +} + +const char * +getcert(const char *uri) +{ + int i; + + for (i = 0; i < LENGTH(certs); ++i) { + if (certs[i].regex && + !regexec(&(certs[i].re), uri, 0, NULL, 0)) + return certs[i].file; + } + + return NULL; +} + +void +setcert(Client *c, const char *uri) +{ + const char *file = getcert(uri); + char *host; + GTlsCertificate *cert; + + if (!file) + return; + + if (!(cert = g_tls_certificate_new_from_file(file, NULL))) { + fprintf(stderr, "Could not read certificate file: %s\n", file); + return; + } + + if ((uri = strstr(uri, "https://"))) { + uri += sizeof("https://") - 1; + host = g_strndup(uri, strchr(uri, '/') - uri); + webkit_web_context_allow_tls_certificate_for_host(c->context, + cert, host); + g_free(host); + } + + g_object_unref(cert); + +} + +const char * +getstyle(const char *uri) +{ + int i; + + if (stylefile) + return stylefile; + + for (i = 0; i < LENGTH(styles); ++i) { + if (styles[i].regex && + !regexec(&(styles[i].re), uri, 0, NULL, 0)) + return styles[i].file; + } + + return ""; +} + +void +setstyle(Client *c, const char *file) +{ + gchar *style; + + if (!g_file_get_contents(file, &style, NULL, NULL)) { + fprintf(stderr, "Could not read style file: %s\n", file); + return; + } + + webkit_user_content_manager_add_style_sheet( + webkit_web_view_get_user_content_manager(c->view), + webkit_user_style_sheet_new(style, + WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, + WEBKIT_USER_STYLE_LEVEL_USER, + NULL, NULL)); + + g_free(style); +} + +void +runscript(Client *c) +{ + gchar *script; + gsize l; + + if (g_file_get_contents(scriptfile, &script, &l, NULL) && l) + evalscript(c, "%s", script); + g_free(script); +} + +void +evalscript(Client *c, const char *jsstr, ...) +{ + va_list ap; + gchar *script; + + va_start(ap, jsstr); + script = g_strdup_vprintf(jsstr, ap); + va_end(ap); + + webkit_web_view_evaluate_javascript(c->view, script, -1, + NULL, NULL, NULL, NULL, NULL); + g_free(script); +} + +void +updatewinid(Client *c) +{ + snprintf(winid, LENGTH(winid), "%lu", c->xid); +} + +void +handleplumb(Client *c, const char *uri) +{ + Arg a = (Arg)PLUMB(uri); + spawn(c, &a); +} + +void +newwindow(Client *c, const Arg *a, int noembed) +{ + int i = 0; + char tmp[64]; + const char *cmd[29], *uri; + const Arg arg = { .v = cmd }; + + cmd[i++] = argv0; + cmd[i++] = "-a"; + cmd[i++] = curconfig[CookiePolicies].val.v; + cmd[i++] = curconfig[ScrollBars].val.i ? "-B" : "-b"; + if (cookiefile && g_strcmp0(cookiefile, "")) { + cmd[i++] = "-c"; + cmd[i++] = cookiefile; + } + if (stylefile && g_strcmp0(stylefile, "")) { + cmd[i++] = "-C"; + cmd[i++] = stylefile; + } + cmd[i++] = curconfig[DiskCache].val.i ? "-D" : "-d"; + if (embed && !noembed) { + cmd[i++] = "-e"; + snprintf(tmp, LENGTH(tmp), "%lu", embed); + cmd[i++] = tmp; + } + cmd[i++] = curconfig[RunInFullscreen].val.i ? "-F" : "-f" ; + cmd[i++] = curconfig[Geolocation].val.i ? "-G" : "-g" ; + cmd[i++] = curconfig[LoadImages].val.i ? "-I" : "-i" ; + cmd[i++] = curconfig[KioskMode].val.i ? "-K" : "-k" ; + cmd[i++] = curconfig[Style].val.i ? "-M" : "-m" ; + cmd[i++] = curconfig[Inspector].val.i ? "-N" : "-n" ; + if (scriptfile && g_strcmp0(scriptfile, "")) { + cmd[i++] = "-r"; + cmd[i++] = scriptfile; + } + cmd[i++] = curconfig[JavaScript].val.i ? "-S" : "-s"; + cmd[i++] = curconfig[StrictTLS].val.i ? "-T" : "-t"; + if (fulluseragent && g_strcmp0(fulluseragent, "")) { + cmd[i++] = "-u"; + cmd[i++] = fulluseragent; + } + if (showxid) + cmd[i++] = "-w"; + cmd[i++] = curconfig[Certificate].val.i ? "-X" : "-x" ; + /* do not keep zoom level */ + cmd[i++] = "--"; + if ((uri = a->v)) + cmd[i++] = uri; + cmd[i] = NULL; + + spawn(c, &arg); +} + +void +spawn(Client *c, const Arg *a) +{ + if (fork() == 0) { + if (dpy) + close(ConnectionNumber(dpy)); + close(spair[0]); + close(spair[1]); + setsid(); + execvp(((char **)a->v)[0], (char **)a->v); + fprintf(stderr, "%s: execvp %s", argv0, ((char **)a->v)[0]); + perror(" failed"); + exit(1); + } +} + +void +destroyclient(Client *c) +{ + Client *p; + + webkit_web_view_stop_loading(c->view); + /* Not needed, has already been called + gtk_widget_destroy(c->win); + */ + + for (p = clients; p && p->next != c; p = p->next) + ; + if (p) + p->next = c->next; + else + clients = c->next; + free(c); +} + +void +cleanup(void) +{ + while (clients) + destroyclient(clients); + + close(spair[0]); + close(spair[1]); + g_free(cookiefile); + g_free(scriptfile); + g_free(stylefile); + g_free(cachedir); + XCloseDisplay(dpy); +} + +WebKitWebView * +newview(Client *c, WebKitWebView *rv) +{ + WebKitWebView *v; + WebKitSettings *settings; + WebKitWebContext *context; + WebKitCookieManager *cookiemanager; + WebKitUserContentManager *contentmanager; + + /* Webview */ + if (rv) { + v = WEBKIT_WEB_VIEW(webkit_web_view_new_with_related_view(rv)); + context = webkit_web_view_get_context(v); + settings = webkit_web_view_get_settings(v); + } else { + settings = webkit_settings_new_with_settings( + "allow-file-access-from-file-urls", curconfig[FileURLsCrossAccess].val.i, + "allow-universal-access-from-file-urls", curconfig[FileURLsCrossAccess].val.i, + "auto-load-images", curconfig[LoadImages].val.i, + "default-charset", curconfig[DefaultCharset].val.v, + "default-font-size", curconfig[FontSize].val.i, + "enable-caret-browsing", curconfig[CaretBrowsing].val.i, + "enable-developer-extras", curconfig[Inspector].val.i, + "enable-dns-prefetching", curconfig[DNSPrefetch].val.i, + "enable-html5-database", curconfig[DiskCache].val.i, + "enable-html5-local-storage", curconfig[DiskCache].val.i, + "enable-javascript", curconfig[JavaScript].val.i, + "enable-site-specific-quirks", curconfig[SiteQuirks].val.i, + "enable-smooth-scrolling", curconfig[SmoothScrolling].val.i, + "enable-webgl", curconfig[WebGL].val.i, + "media-playback-requires-user-gesture", curconfig[MediaManualPlay].val.i, + NULL); +/* For more interesting settings, have a look at + * http://webkitgtk.org/reference/webkit2gtk/stable/WebKitSettings.html */ + + if (strcmp(fulluseragent, "")) { + webkit_settings_set_user_agent(settings, fulluseragent); + } else if (surfuseragent) { + webkit_settings_set_user_agent_with_application_details( + settings, "Surf", VERSION); + } + useragent = webkit_settings_get_user_agent(settings); + + contentmanager = webkit_user_content_manager_new(); + + if (curconfig[Ephemeral].val.i) { + context = webkit_web_context_new_ephemeral(); + } else { + context = webkit_web_context_new_with_website_data_manager( + webkit_website_data_manager_new( + "base-cache-directory", cachedir, + "base-data-directory", cachedir, + NULL)); + } + + cookiemanager = webkit_web_context_get_cookie_manager(context); + + /* TLS */ + webkit_website_data_manager_set_tls_errors_policy( + webkit_web_context_get_website_data_manager(context), + curconfig[StrictTLS].val.i ? WEBKIT_TLS_ERRORS_POLICY_FAIL : + WEBKIT_TLS_ERRORS_POLICY_IGNORE); + /* disk cache */ + webkit_web_context_set_cache_model(context, + curconfig[DiskCache].val.i ? WEBKIT_CACHE_MODEL_WEB_BROWSER : + WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER); + + /* Currently only works with text file to be compatible with curl */ + if (!curconfig[Ephemeral].val.i) + webkit_cookie_manager_set_persistent_storage(cookiemanager, + cookiefile, WEBKIT_COOKIE_PERSISTENT_STORAGE_TEXT); + /* cookie policy */ + webkit_cookie_manager_set_accept_policy(cookiemanager, + cookiepolicy_get()); + /* languages */ + webkit_web_context_set_preferred_languages(context, + curconfig[PreferredLanguages].val.v); + webkit_web_context_set_spell_checking_languages(context, + curconfig[SpellLanguages].val.v); + webkit_web_context_set_spell_checking_enabled(context, + curconfig[SpellChecking].val.i); + + g_signal_connect(G_OBJECT(context), "download-started", + G_CALLBACK(downloadstarted), c); + g_signal_connect(G_OBJECT(context), "initialize-web-extensions", + G_CALLBACK(initwebextensions), c); + + v = g_object_new(WEBKIT_TYPE_WEB_VIEW, + "settings", settings, + "user-content-manager", contentmanager, + "web-context", context, + NULL); + } + + g_signal_connect(G_OBJECT(v), "notify::estimated-load-progress", + G_CALLBACK(progresschanged), c); + g_signal_connect(G_OBJECT(v), "notify::title", + G_CALLBACK(titlechanged), c); + g_signal_connect(G_OBJECT(v), "button-release-event", + G_CALLBACK(buttonreleased), c); + g_signal_connect(G_OBJECT(v), "close", + G_CALLBACK(closeview), c); + g_signal_connect(G_OBJECT(v), "create", + G_CALLBACK(createview), c); + g_signal_connect(G_OBJECT(v), "decide-policy", + G_CALLBACK(decidepolicy), c); + g_signal_connect(G_OBJECT(v), "insecure-content-detected", + G_CALLBACK(insecurecontent), c); + g_signal_connect(G_OBJECT(v), "load-failed-with-tls-errors", + G_CALLBACK(loadfailedtls), c); + g_signal_connect(G_OBJECT(v), "load-changed", + G_CALLBACK(loadchanged), c); + g_signal_connect(G_OBJECT(v), "mouse-target-changed", + G_CALLBACK(mousetargetchanged), c); + g_signal_connect(G_OBJECT(v), "permission-request", + G_CALLBACK(permissionrequested), c); + g_signal_connect(G_OBJECT(v), "ready-to-show", + G_CALLBACK(showview), c); + g_signal_connect(G_OBJECT(v), "user-message-received", + G_CALLBACK(viewusrmsgrcv), c); + g_signal_connect(G_OBJECT(v), "web-process-terminated", + G_CALLBACK(webprocessterminated), c); + + c->context = context; + c->settings = settings; + + setparameter(c, 0, DarkMode, &curconfig[DarkMode].val); + + return v; +} + +void +initwebextensions(WebKitWebContext *wc, Client *c) +{ + webkit_web_context_set_web_extensions_directory(wc, WEBEXTDIR); +} + +GtkWidget * +createview(WebKitWebView *v, WebKitNavigationAction *a, Client *c) +{ + Client *n; + + switch (webkit_navigation_action_get_navigation_type(a)) { + case WEBKIT_NAVIGATION_TYPE_OTHER: /* fallthrough */ + /* + * popup windows of type “other” are almost always triggered + * by user gesture, so inverse the logic here + */ +/* instead of this, compare destination uri to mouse-over uri for validating window */ + if (webkit_navigation_action_is_user_gesture(a)) + return NULL; + case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_RELOAD: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED: + n = newclient(c); + break; + default: + return NULL; + } + + return GTK_WIDGET(n->view); +} + +gboolean +buttonreleased(GtkWidget *w, GdkEvent *e, Client *c) +{ + WebKitHitTestResultContext element; + int i; + + element = webkit_hit_test_result_get_context(c->mousepos); + + for (i = 0; i < LENGTH(buttons); ++i) { + if (element & buttons[i].target && + e->button.button == buttons[i].button && + CLEANMASK(e->button.state) == CLEANMASK(buttons[i].mask) && + buttons[i].func) { + buttons[i].func(c, &buttons[i].arg, c->mousepos); + return buttons[i].stopevent; + } + } + + return FALSE; +} + +GdkFilterReturn +processx(GdkXEvent *e, GdkEvent *event, gpointer d) +{ + Client *c = (Client *)d; + XPropertyEvent *ev; + Arg a; + + if (((XEvent *)e)->type == PropertyNotify) { + ev = &((XEvent *)e)->xproperty; + if (ev->state == PropertyNewValue) { + if (ev->atom == atoms[AtomFind]) { + find(c, NULL); + + return GDK_FILTER_REMOVE; + } else if (ev->atom == atoms[AtomGo]) { + a.v = getatom(c, AtomGo); + loaduri(c, &a); + + return GDK_FILTER_REMOVE; + } + } + } + return GDK_FILTER_CONTINUE; +} + +gboolean +winevent(GtkWidget *w, GdkEvent *e, Client *c) +{ + int i; + + switch (e->type) { + case GDK_ENTER_NOTIFY: + c->overtitle = c->targeturi; + updatetitle(c); + break; + case GDK_KEY_PRESS: + if (!curconfig[KioskMode].val.i && + !insertmode || + CLEANMASK(e->key.state) == (MODKEY|GDK_SHIFT_MASK) || + CLEANMASK(e->key.state) == (MODKEY) || + gdk_keyval_to_lower(e->key.keyval) == (GDK_KEY_Escape)) { + for (i = 0; i < LENGTH(keys); ++i) { + if (gdk_keyval_to_lower(e->key.keyval) == + keys[i].keyval && + CLEANMASK(e->key.state) == keys[i].mod && + keys[i].func) { + updatewinid(c); + keys[i].func(c, &(keys[i].arg)); + return TRUE; + } + } + } + case GDK_LEAVE_NOTIFY: + c->overtitle = NULL; + updatetitle(c); + break; + case GDK_WINDOW_STATE: + if (e->window_state.changed_mask == + GDK_WINDOW_STATE_FULLSCREEN) + c->fullscreen = e->window_state.new_window_state & + GDK_WINDOW_STATE_FULLSCREEN; + break; + default: + break; + } + + return FALSE; +} + +void +showview(WebKitWebView *v, Client *c) +{ + GdkRGBA bgcolor = { 0 }; + GdkWindow *gwin; + + c->finder = webkit_web_view_get_find_controller(c->view); + c->inspector = webkit_web_view_get_inspector(c->view); + + c->pageid = webkit_web_view_get_page_id(c->view); + c->win = createwindow(c); + + gtk_container_add(GTK_CONTAINER(c->win), GTK_WIDGET(c->view)); + gtk_widget_show_all(c->win); + gtk_widget_grab_focus(GTK_WIDGET(c->view)); + + gwin = gtk_widget_get_window(GTK_WIDGET(c->win)); + c->xid = gdk_x11_window_get_xid(gwin); + updatewinid(c); + if (showxid) { + gdk_display_sync(gtk_widget_get_display(c->win)); + puts(winid); + fflush(stdout); + } + + if (curconfig[HideBackground].val.i) + webkit_web_view_set_background_color(c->view, &bgcolor); + + if (!curconfig[KioskMode].val.i) { + gdk_window_set_events(gwin, GDK_ALL_EVENTS_MASK); + gdk_window_add_filter(gwin, processx, c); + } + + if (curconfig[RunInFullscreen].val.i) + togglefullscreen(c, NULL); + + if (curconfig[ZoomLevel].val.f != 1.0) + webkit_web_view_set_zoom_level(c->view, + curconfig[ZoomLevel].val.f); + + setatom(c, AtomFind, ""); + setatom(c, AtomUri, "about:blank"); +} + +GtkWidget * +createwindow(Client *c) +{ + char *wmstr; + GtkWidget *w; + + if (embed) { + w = gtk_plug_new(embed); + } else { + w = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + wmstr = g_path_get_basename(argv0); + gtk_window_set_wmclass(GTK_WINDOW(w), wmstr, "Surf"); + g_free(wmstr); + + wmstr = g_strdup_printf("%s[%"PRIu64"]", "Surf", c->pageid); + gtk_window_set_role(GTK_WINDOW(w), wmstr); + g_free(wmstr); + + gtk_window_set_default_size(GTK_WINDOW(w), winsize[0], winsize[1]); + } + + g_signal_connect(G_OBJECT(w), "destroy", + G_CALLBACK(destroywin), c); + g_signal_connect(G_OBJECT(w), "enter-notify-event", + G_CALLBACK(winevent), c); + g_signal_connect(G_OBJECT(w), "key-press-event", + G_CALLBACK(winevent), c); + g_signal_connect(G_OBJECT(w), "leave-notify-event", + G_CALLBACK(winevent), c); + g_signal_connect(G_OBJECT(w), "window-state-event", + G_CALLBACK(winevent), c); + + return w; +} + +gboolean +loadfailedtls(WebKitWebView *v, gchar *uri, GTlsCertificate *cert, + GTlsCertificateFlags err, Client *c) +{ + GString *errmsg = g_string_new(NULL); + gchar *html, *pem; + + c->failedcert = g_object_ref(cert); + c->tlserr = err; + c->errorpage = 1; + + if (err & G_TLS_CERTIFICATE_UNKNOWN_CA) + g_string_append(errmsg, + "The signing certificate authority is not known.
"); + if (err & G_TLS_CERTIFICATE_BAD_IDENTITY) + g_string_append(errmsg, + "The certificate does not match the expected identity " + "of the site that it was retrieved from.
"); + if (err & G_TLS_CERTIFICATE_NOT_ACTIVATED) + g_string_append(errmsg, + "The certificate's activation time " + "is still in the future.
"); + if (err & G_TLS_CERTIFICATE_EXPIRED) + g_string_append(errmsg, "The certificate has expired.
"); + if (err & G_TLS_CERTIFICATE_REVOKED) + g_string_append(errmsg, + "The certificate has been revoked according to " + "the GTlsConnection's certificate revocation list.
"); + if (err & G_TLS_CERTIFICATE_INSECURE) + g_string_append(errmsg, + "The certificate's algorithm is considered insecure.
"); + if (err & G_TLS_CERTIFICATE_GENERIC_ERROR) + g_string_append(errmsg, + "Some error occurred validating the certificate.
"); + + g_object_get(cert, "certificate-pem", &pem, NULL); + html = g_strdup_printf("

Could not validate TLS for “%s”
%s

" + "

You can inspect the following certificate " + "with Ctrl-t (default keybinding).

" + "

%s

", uri, errmsg->str, pem); + g_free(pem); + g_string_free(errmsg, TRUE); + + webkit_web_view_load_alternate_html(c->view, html, uri, NULL); + g_free(html); + + return TRUE; +} + +void +loadchanged(WebKitWebView *v, WebKitLoadEvent e, Client *c) +{ + const char *uri = geturi(c); + + switch (e) { + case WEBKIT_LOAD_STARTED: + setatom(c, AtomUri, uri); + c->title = uri; + c->https = c->insecure = 0; + seturiparameters(c, uri, loadtransient); + if (c->errorpage) + c->errorpage = 0; + else + g_clear_object(&c->failedcert); + break; + case WEBKIT_LOAD_REDIRECTED: + setatom(c, AtomUri, uri); + c->title = uri; + seturiparameters(c, uri, loadtransient); + break; + case WEBKIT_LOAD_COMMITTED: + setatom(c, AtomUri, uri); + c->title = uri; + seturiparameters(c, uri, loadcommitted); + c->https = webkit_web_view_get_tls_info(c->view, &c->cert, + &c->tlserr); + break; + case WEBKIT_LOAD_FINISHED: + seturiparameters(c, uri, loadfinished); + /* Disabled until we write some WebKitWebExtension for + * manipulating the DOM directly. + evalscript(c, "document.documentElement.style.overflow = '%s'", + enablescrollbars ? "auto" : "hidden"); + */ + runscript(c); + break; + } + updatetitle(c); +} + +void +progresschanged(WebKitWebView *v, GParamSpec *ps, Client *c) +{ + c->progress = webkit_web_view_get_estimated_load_progress(c->view) * + 100; + updatetitle(c); +} + +void +titlechanged(WebKitWebView *view, GParamSpec *ps, Client *c) +{ + c->title = webkit_web_view_get_title(c->view); + updatetitle(c); +} + +gboolean +viewusrmsgrcv(WebKitWebView *v, WebKitUserMessage *m, gpointer unused) +{ + WebKitUserMessage *r; + GUnixFDList *gfd; + const char *name; + + name = webkit_user_message_get_name(m); + if (strcmp(name, "page-created") != 0) { + fprintf(stderr, "surf: Unknown UserMessage: %s\n", name); + return TRUE; + } + + if (spair[1] < 0) + return TRUE; + + gfd = g_unix_fd_list_new_from_array(&spair[1], 1); + r = webkit_user_message_new_with_fd_list("surf-pipe", NULL, gfd); + + webkit_user_message_send_reply(m, r); + + return TRUE; +} + +void +mousetargetchanged(WebKitWebView *v, WebKitHitTestResult *h, guint modifiers, + Client *c) +{ + WebKitHitTestResultContext hc = webkit_hit_test_result_get_context(h); + + /* Keep the hit test to know where is the pointer on the next click */ + c->mousepos = h; + + if (hc & OnLink) + c->targeturi = webkit_hit_test_result_get_link_uri(h); + else if (hc & OnImg) + c->targeturi = webkit_hit_test_result_get_image_uri(h); + else if (hc & OnMedia) + c->targeturi = webkit_hit_test_result_get_media_uri(h); + else + c->targeturi = NULL; + + c->overtitle = c->targeturi; + updatetitle(c); +} + +gboolean +permissionrequested(WebKitWebView *v, WebKitPermissionRequest *r, Client *c) +{ + ParamName param = ParameterLast; + + if (WEBKIT_IS_GEOLOCATION_PERMISSION_REQUEST(r)) { + param = Geolocation; + } else if (WEBKIT_IS_USER_MEDIA_PERMISSION_REQUEST(r)) { + if (webkit_user_media_permission_is_for_audio_device( + WEBKIT_USER_MEDIA_PERMISSION_REQUEST(r))) + param = AccessMicrophone; + else if (webkit_user_media_permission_is_for_video_device( + WEBKIT_USER_MEDIA_PERMISSION_REQUEST(r))) + param = AccessWebcam; + } else { + return FALSE; + } + + if (curconfig[param].val.i) + webkit_permission_request_allow(r); + else + webkit_permission_request_deny(r); + + return TRUE; +} + +gboolean +decidepolicy(WebKitWebView *v, WebKitPolicyDecision *d, + WebKitPolicyDecisionType dt, Client *c) +{ + switch (dt) { + case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION: + decidenavigation(d, c); + break; + case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION: + decidenewwindow(d, c); + break; + case WEBKIT_POLICY_DECISION_TYPE_RESPONSE: + decideresource(d, c); + break; + default: + webkit_policy_decision_ignore(d); + break; + } + return TRUE; +} + +void +decidenavigation(WebKitPolicyDecision *d, Client *c) +{ + WebKitNavigationAction *a = + webkit_navigation_policy_decision_get_navigation_action( + WEBKIT_NAVIGATION_POLICY_DECISION(d)); + + switch (webkit_navigation_action_get_navigation_type(a)) { + case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_RELOAD: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_OTHER: /* fallthrough */ + default: + /* Do not navigate to links with a "_blank" target (popup) */ + if (webkit_navigation_action_get_frame_name(a)) { + webkit_policy_decision_ignore(d); + } else { + /* Filter out navigation to different domain ? */ + /* get action→urirequest, copy and load in new window+view + * on Ctrl+Click ? */ + webkit_policy_decision_use(d); + } + break; + } +} + +void +decidenewwindow(WebKitPolicyDecision *d, Client *c) +{ + Arg arg; + WebKitNavigationAction *a = + webkit_navigation_policy_decision_get_navigation_action( + WEBKIT_NAVIGATION_POLICY_DECISION(d)); + + + switch (webkit_navigation_action_get_navigation_type(a)) { + case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_RELOAD: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED: + /* Filter domains here */ +/* If the value of “mouse-button” is not 0, then the navigation was triggered by a mouse event. + * test for link clicked but no button ? */ + arg.v = webkit_uri_request_get_uri( + webkit_navigation_action_get_request(a)); + newwindow(c, &arg, 0); + break; + case WEBKIT_NAVIGATION_TYPE_OTHER: /* fallthrough */ + default: + break; + } + + webkit_policy_decision_ignore(d); +} + +void +decideresource(WebKitPolicyDecision *d, Client *c) +{ + int i, isascii = 1; + WebKitResponsePolicyDecision *r = WEBKIT_RESPONSE_POLICY_DECISION(d); + WebKitURIResponse *res = + webkit_response_policy_decision_get_response(r); + const gchar *uri = webkit_uri_response_get_uri(res); + + if (g_str_has_suffix(uri, "/favicon.ico")) { + webkit_policy_decision_ignore(d); + return; + } + + if (!g_str_has_prefix(uri, "http://") + && !g_str_has_prefix(uri, "https://") + && !g_str_has_prefix(uri, "about:") + && !g_str_has_prefix(uri, "file://") + && !g_str_has_prefix(uri, "webkit://") + && !g_str_has_prefix(uri, "data:") + && !g_str_has_prefix(uri, "blob:") + && strlen(uri) > 0) { + for (i = 0; i < strlen(uri); i++) { + if (!g_ascii_isprint(uri[i])) { + isascii = 0; + break; + } + } + if (isascii) { + handleplumb(c, uri); + webkit_policy_decision_ignore(d); + return; + } + } + + if (webkit_response_policy_decision_is_mime_type_supported(r)) { + webkit_policy_decision_use(d); + } else { + webkit_policy_decision_ignore(d); + download(c, res); + } +} + +void +insecurecontent(WebKitWebView *v, WebKitInsecureContentEvent e, Client *c) +{ + c->insecure = 1; +} + +void +downloadstarted(WebKitWebContext *wc, WebKitDownload *d, Client *c) +{ + g_signal_connect(G_OBJECT(d), "notify::response", + G_CALLBACK(responsereceived), c); +} + +void +responsereceived(WebKitDownload *d, GParamSpec *ps, Client *c) +{ + download(c, webkit_download_get_response(d)); + webkit_download_cancel(d); +} + +void +download(Client *c, WebKitURIResponse *r) +{ + Arg a = (Arg)DOWNLOAD(webkit_uri_response_get_uri(r), geturi(c)); + spawn(c, &a); +} + +void +webprocessterminated(WebKitWebView *v, WebKitWebProcessTerminationReason r, + Client *c) +{ + fprintf(stderr, "web process terminated: %s\n", + r == WEBKIT_WEB_PROCESS_CRASHED ? "crashed" : "no memory"); + closeview(v, c); +} + +void +closeview(WebKitWebView *v, Client *c) +{ + gtk_widget_destroy(c->win); +} + +void +destroywin(GtkWidget* w, Client *c) +{ + destroyclient(c); + if (!clients) + gtk_main_quit(); +} + +void +pasteuri(GtkClipboard *clipboard, const char *text, gpointer d) +{ + Arg a = {.v = text }; + if (text) + loaduri((Client *) d, &a); +} + +void +reload(Client *c, const Arg *a) +{ + if (a->i) + webkit_web_view_reload_bypass_cache(c->view); + else + webkit_web_view_reload(c->view); +} + +void +print(Client *c, const Arg *a) +{ + webkit_print_operation_run_dialog(webkit_print_operation_new(c->view), + GTK_WINDOW(c->win)); +} + +void +showcert(Client *c, const Arg *a) +{ + GTlsCertificate *cert = c->failedcert ? c->failedcert : c->cert; + GcrCertificate *gcrt; + GByteArray *crt; + GtkWidget *win; + GcrCertificateWidget *wcert; + + if (!cert) + return; + + g_object_get(cert, "certificate", &crt, NULL); + gcrt = gcr_simple_certificate_new(crt->data, crt->len); + g_byte_array_unref(crt); + + win = gtk_window_new(GTK_WINDOW_TOPLEVEL); + wcert = gcr_certificate_widget_new(gcrt); + g_object_unref(gcrt); + + gtk_container_add(GTK_CONTAINER(win), GTK_WIDGET(wcert)); + gtk_widget_show_all(win); +} + +void +clipboard(Client *c, const Arg *a) +{ + if (a->i) { /* load clipboard uri */ + gtk_clipboard_request_text(gtk_clipboard_get( + GDK_SELECTION_PRIMARY), + pasteuri, c); + } else { /* copy uri */ + gtk_clipboard_set_text(gtk_clipboard_get( + GDK_SELECTION_PRIMARY), c->targeturi + ? c->targeturi : geturi(c), -1); + } +} + +void +zoom(Client *c, const Arg *a) +{ + if (a->i > 0) + webkit_web_view_set_zoom_level(c->view, + curconfig[ZoomLevel].val.f + 0.1); + else if (a->i < 0) + webkit_web_view_set_zoom_level(c->view, + curconfig[ZoomLevel].val.f - 0.1); + else + webkit_web_view_set_zoom_level(c->view, 1.0); + + curconfig[ZoomLevel].val.f = webkit_web_view_get_zoom_level(c->view); +} + +static void +msgext(Client *c, char type, const Arg *a) +{ + static unsigned char msg[MSGBUFSZ]; + int ret; + + if (spair[0] < 0) + return; + + ret = snprintf(msg, sizeof(msg), "%c%c%c", + (unsigned char)c->pageid, type, (signed char)a->i); + if (ret >= sizeof(msg)) { + fprintf(stderr, "surf: message too long: %d\n", ret); + return; + } + + if (send(spair[0], msg, ret, 0) != ret) + fprintf(stderr, "surf: error sending: %hhu/%c/%d (%d)\n", + (unsigned char)c->pageid, type, a->i, ret); +} + +void +scrollv(Client *c, const Arg *a) +{ + msgext(c, 'v', a); +} + +void +scrollh(Client *c, const Arg *a) +{ + msgext(c, 'h', a); +} + +void +navigate(Client *c, const Arg *a) +{ + if (a->i < 0) + webkit_web_view_go_back(c->view); + else if (a->i > 0) + webkit_web_view_go_forward(c->view); +} + +void +stop(Client *c, const Arg *a) +{ + webkit_web_view_stop_loading(c->view); +} + +void +toggle(Client *c, const Arg *a) +{ + curconfig[a->i].val.i ^= 1; + setparameter(c, 1, (ParamName)a->i, &curconfig[a->i].val); +} + +void +togglefullscreen(Client *c, const Arg *a) +{ + /* toggling value is handled in winevent() */ + if (c->fullscreen) + gtk_window_unfullscreen(GTK_WINDOW(c->win)); + else + gtk_window_fullscreen(GTK_WINDOW(c->win)); +} + +void +togglecookiepolicy(Client *c, const Arg *a) +{ + ++cookiepolicy; + cookiepolicy %= strlen(curconfig[CookiePolicies].val.v); + + setparameter(c, 0, CookiePolicies, NULL); +} + +void +toggleinspector(Client *c, const Arg *a) +{ + if (webkit_web_inspector_is_attached(c->inspector)) + webkit_web_inspector_close(c->inspector); + else if (curconfig[Inspector].val.i) + webkit_web_inspector_show(c->inspector); +} + +void +find(Client *c, const Arg *a) +{ + const char *s, *f; + + if (a && a->i) { + if (a->i > 0) + webkit_find_controller_search_next(c->finder); + else + webkit_find_controller_search_previous(c->finder); + } else { + s = getatom(c, AtomFind); + f = webkit_find_controller_get_search_text(c->finder); + + if (g_strcmp0(f, s) == 0) /* reset search */ + webkit_find_controller_search(c->finder, "", findopts, + G_MAXUINT); + + webkit_find_controller_search(c->finder, s, findopts, + G_MAXUINT); + + if (strcmp(s, "") == 0) + webkit_find_controller_search_finish(c->finder); + } +} + +void +insert(Client *c, const Arg *a) +{ + insertmode = (a->i); +} + +void +clicknavigate(Client *c, const Arg *a, WebKitHitTestResult *h) +{ + navigate(c, a); +} + +void +clicknewwindow(Client *c, const Arg *a, WebKitHitTestResult *h) +{ + Arg arg; + + arg.v = webkit_hit_test_result_get_link_uri(h); + newwindow(c, &arg, a->i); +} + +void +clickexternplayer(Client *c, const Arg *a, WebKitHitTestResult *h) +{ + Arg arg; + + arg = (Arg)VIDEOPLAY(webkit_hit_test_result_get_media_uri(h)); + spawn(c, &arg); +} + +int +main(int argc, char *argv[]) +{ + Arg arg; + Client *c; + + memset(&arg, 0, sizeof(arg)); + + /* command line args */ + ARGBEGIN { + case 'a': + defconfig[CookiePolicies].val.v = EARGF(usage()); + defconfig[CookiePolicies].prio = 2; + break; + case 'b': + defconfig[ScrollBars].val.i = 0; + defconfig[ScrollBars].prio = 2; + break; + case 'B': + defconfig[ScrollBars].val.i = 1; + defconfig[ScrollBars].prio = 2; + break; + case 'c': + cookiefile = EARGF(usage()); + break; + case 'C': + stylefile = EARGF(usage()); + break; + case 'd': + defconfig[DiskCache].val.i = 0; + defconfig[DiskCache].prio = 2; + break; + case 'D': + defconfig[DiskCache].val.i = 1; + defconfig[DiskCache].prio = 2; + break; + case 'e': + embed = strtol(EARGF(usage()), NULL, 0); + break; + case 'f': + defconfig[RunInFullscreen].val.i = 0; + defconfig[RunInFullscreen].prio = 2; + break; + case 'F': + defconfig[RunInFullscreen].val.i = 1; + defconfig[RunInFullscreen].prio = 2; + break; + case 'g': + defconfig[Geolocation].val.i = 0; + defconfig[Geolocation].prio = 2; + break; + case 'G': + defconfig[Geolocation].val.i = 1; + defconfig[Geolocation].prio = 2; + break; + case 'i': + defconfig[LoadImages].val.i = 0; + defconfig[LoadImages].prio = 2; + break; + case 'I': + defconfig[LoadImages].val.i = 1; + defconfig[LoadImages].prio = 2; + break; + case 'k': + defconfig[KioskMode].val.i = 0; + defconfig[KioskMode].prio = 2; + break; + case 'K': + defconfig[KioskMode].val.i = 1; + defconfig[KioskMode].prio = 2; + break; + case 'm': + defconfig[Style].val.i = 0; + defconfig[Style].prio = 2; + break; + case 'M': + defconfig[Style].val.i = 1; + defconfig[Style].prio = 2; + break; + case 'n': + defconfig[Inspector].val.i = 0; + defconfig[Inspector].prio = 2; + break; + case 'N': + defconfig[Inspector].val.i = 1; + defconfig[Inspector].prio = 2; + break; + case 'r': + scriptfile = EARGF(usage()); + break; + case 's': + defconfig[JavaScript].val.i = 0; + defconfig[JavaScript].prio = 2; + break; + case 'S': + defconfig[JavaScript].val.i = 1; + defconfig[JavaScript].prio = 2; + break; + case 't': + defconfig[StrictTLS].val.i = 0; + defconfig[StrictTLS].prio = 2; + break; + case 'T': + defconfig[StrictTLS].val.i = 1; + defconfig[StrictTLS].prio = 2; + break; + case 'u': + fulluseragent = EARGF(usage()); + break; + case 'v': + die("surf-"VERSION", see LICENSE for © details\n"); + case 'w': + showxid = 1; + break; + case 'x': + defconfig[Certificate].val.i = 0; + defconfig[Certificate].prio = 2; + break; + case 'X': + defconfig[Certificate].val.i = 1; + defconfig[Certificate].prio = 2; + break; + case 'z': + defconfig[ZoomLevel].val.f = strtof(EARGF(usage()), NULL); + defconfig[ZoomLevel].prio = 2; + break; + default: + usage(); + } ARGEND; + if (argc > 0) + arg.v = argv[0]; + else + arg.v = "about:blank"; + + setup(); + c = newclient(NULL); + showview(NULL, c); + + loaduri(c, &arg); + updatetitle(c); + + gtk_main(); + cleanup(); + + return 0; +} diff --git a/stuff/manual-programs/suckless/surf/surf.c.orig b/stuff/manual-programs/suckless/surf/surf.c.orig new file mode 100644 index 0000000..594a658 --- /dev/null +++ b/stuff/manual-programs/suckless/surf/surf.c.orig @@ -0,0 +1,2143 @@ +/* See LICENSE file for copyright and license details. + * + * To understand surf, start reading main(). + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "arg.h" +#include "common.h" + +#define LENGTH(x) (sizeof(x) / sizeof(x[0])) +#define CLEANMASK(mask) (mask & (MODKEY|GDK_SHIFT_MASK)) + +enum { AtomFind, AtomGo, AtomUri, AtomUTF8, AtomLast }; + +enum { + OnDoc = WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT, + OnLink = WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK, + OnImg = WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE, + OnMedia = WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA, + OnEdit = WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE, + OnBar = WEBKIT_HIT_TEST_RESULT_CONTEXT_SCROLLBAR, + OnSel = WEBKIT_HIT_TEST_RESULT_CONTEXT_SELECTION, + OnAny = OnDoc | OnLink | OnImg | OnMedia | OnEdit | OnBar | OnSel, +}; + +typedef enum { + AccessMicrophone, + AccessWebcam, + CaretBrowsing, + Certificate, + CookiePolicies, + DarkMode, + DiskCache, + DefaultCharset, + DNSPrefetch, + Ephemeral, + FileURLsCrossAccess, + FontSize, + Geolocation, + HideBackground, + Inspector, + JavaScript, + KioskMode, + LoadImages, + MediaManualPlay, + PreferredLanguages, + RunInFullscreen, + ScrollBars, + ShowIndicators, + SiteQuirks, + SmoothScrolling, + SpellChecking, + SpellLanguages, + StrictTLS, + Style, + WebGL, + ZoomLevel, + ParameterLast +} ParamName; + +typedef union { + int i; + float f; + const void *v; +} Arg; + +typedef struct { + Arg val; + int prio; +} Parameter; + +typedef struct Client { + GtkWidget *win; + WebKitWebView *view; + WebKitSettings *settings; + WebKitWebContext *context; + WebKitWebInspector *inspector; + WebKitFindController *finder; + WebKitHitTestResult *mousepos; + GTlsCertificate *cert, *failedcert; + GTlsCertificateFlags tlserr; + Window xid; + guint64 pageid; + int progress, fullscreen, https, insecure, errorpage; + const char *title, *overtitle, *targeturi; + const char *needle; + struct Client *next; +} Client; + +typedef struct { + guint mod; + guint keyval; + void (*func)(Client *c, const Arg *a); + const Arg arg; +} Key; + +typedef struct { + unsigned int target; + unsigned int mask; + guint button; + void (*func)(Client *c, const Arg *a, WebKitHitTestResult *h); + const Arg arg; + unsigned int stopevent; +} Button; + +typedef struct { + const char *uri; + Parameter config[ParameterLast]; + regex_t re; +} UriParameters; + +typedef struct { + char *regex; + char *file; + regex_t re; +} SiteSpecific; + +typedef struct { + const char* alias; + const char* uri; +} Alias; + +/* Surf */ +static void die(const char *errstr, ...); +static void usage(void); +static void setup(void); +static void sigchld(int unused); +static void sighup(int unused); +static char *buildfile(const char *path); +static char *buildpath(const char *path); +static char *untildepath(const char *path); +static const char *getuserhomedir(const char *user); +static const char *getcurrentuserhomedir(void); +static Client *newclient(Client *c); +static void loaduri(Client *c, const Arg *a); +static const char *geturi(Client *c); +static void setatom(Client *c, int a, const char *v); +static const char *getatom(Client *c, int a); +static void updatetitle(Client *c); +static void gettogglestats(Client *c); +static void getpagestats(Client *c); +static WebKitCookieAcceptPolicy cookiepolicy_get(void); +static char cookiepolicy_set(const WebKitCookieAcceptPolicy p); +static void seturiparameters(Client *c, const char *uri, ParamName *params); +static void setparameter(Client *c, int refresh, ParamName p, const Arg *a); +static const char *getcert(const char *uri); +static void setcert(Client *c, const char *file); +static const char *getstyle(const char *uri); +static void setstyle(Client *c, const char *file); +static void runscript(Client *c); +static void evalscript(Client *c, const char *jsstr, ...); +static void updatewinid(Client *c); +static void handleplumb(Client *c, const char *uri); +static void newwindow(Client *c, const Arg *a, int noembed); +static void spawn(Client *c, const Arg *a); +static void msgext(Client *c, char type, const Arg *a); +static void destroyclient(Client *c); +static void cleanup(void); + +/* GTK/WebKit */ +static WebKitWebView *newview(Client *c, WebKitWebView *rv); +static void initwebextensions(WebKitWebContext *wc, Client *c); +static GtkWidget *createview(WebKitWebView *v, WebKitNavigationAction *a, + Client *c); +static gboolean buttonreleased(GtkWidget *w, GdkEvent *e, Client *c); +static GdkFilterReturn processx(GdkXEvent *xevent, GdkEvent *event, + gpointer d); +static gboolean winevent(GtkWidget *w, GdkEvent *e, Client *c); +static void showview(WebKitWebView *v, Client *c); +static GtkWidget *createwindow(Client *c); +static gboolean loadfailedtls(WebKitWebView *v, gchar *uri, + GTlsCertificate *cert, + GTlsCertificateFlags err, Client *c); +static void loadchanged(WebKitWebView *v, WebKitLoadEvent e, Client *c); +static void progresschanged(WebKitWebView *v, GParamSpec *ps, Client *c); +static void titlechanged(WebKitWebView *view, GParamSpec *ps, Client *c); +static void mousetargetchanged(WebKitWebView *v, WebKitHitTestResult *h, + guint modifiers, Client *c); +static gboolean permissionrequested(WebKitWebView *v, + WebKitPermissionRequest *r, Client *c); +static gboolean decidepolicy(WebKitWebView *v, WebKitPolicyDecision *d, + WebKitPolicyDecisionType dt, Client *c); +static void decidenavigation(WebKitPolicyDecision *d, Client *c); +static void decidenewwindow(WebKitPolicyDecision *d, Client *c); +static void decideresource(WebKitPolicyDecision *d, Client *c); +static void insecurecontent(WebKitWebView *v, WebKitInsecureContentEvent e, + Client *c); +static void downloadstarted(WebKitWebContext *wc, WebKitDownload *d, + Client *c); +static void responsereceived(WebKitDownload *d, GParamSpec *ps, Client *c); +static void download(Client *c, WebKitURIResponse *r); +static gboolean viewusrmsgrcv(WebKitWebView *v, WebKitUserMessage *m, + gpointer u); +static void webprocessterminated(WebKitWebView *v, + WebKitWebProcessTerminationReason r, + Client *c); +static void closeview(WebKitWebView *v, Client *c); +static void destroywin(GtkWidget* w, Client *c); + +/* Hotkeys */ +static void pasteuri(GtkClipboard *clipboard, const char *text, gpointer d); +static void reload(Client *c, const Arg *a); +static void print(Client *c, const Arg *a); +static void showcert(Client *c, const Arg *a); +static void clipboard(Client *c, const Arg *a); +static void zoom(Client *c, const Arg *a); +static void scrollv(Client *c, const Arg *a); +static void scrollh(Client *c, const Arg *a); +static void navigate(Client *c, const Arg *a); +static void stop(Client *c, const Arg *a); +static void toggle(Client *c, const Arg *a); +static void togglefullscreen(Client *c, const Arg *a); +static void togglecookiepolicy(Client *c, const Arg *a); +static void toggleinspector(Client *c, const Arg *a); +static void find(Client *c, const Arg *a); + +/* Buttons */ +static void clicknavigate(Client *c, const Arg *a, WebKitHitTestResult *h); +static void clicknewwindow(Client *c, const Arg *a, WebKitHitTestResult *h); +static void clickexternplayer(Client *c, const Arg *a, WebKitHitTestResult *h); + +static char winid[64]; +static char togglestats[11]; +static char pagestats[2]; +static Atom atoms[AtomLast]; +static Window embed; +static int showxid; +static int cookiepolicy; +static Display *dpy; +static Client *clients; +static GdkDevice *gdkkb; +static char *stylefile; +static const char *useragent; +static Parameter *curconfig; +static int modparams[ParameterLast]; +static int spair[2]; +char *argv0; + +static ParamName loadtransient[] = { + Certificate, + CookiePolicies, + DiskCache, + DNSPrefetch, + FileURLsCrossAccess, + JavaScript, + LoadImages, + PreferredLanguages, + ShowIndicators, + StrictTLS, + ParameterLast +}; + +static ParamName loadcommitted[] = { +// AccessMicrophone, +// AccessWebcam, + CaretBrowsing, + DarkMode, + DefaultCharset, + FontSize, + Geolocation, + HideBackground, + Inspector, +// KioskMode, + MediaManualPlay, + RunInFullscreen, + ScrollBars, + SiteQuirks, + SmoothScrolling, + SpellChecking, + SpellLanguages, + Style, + ZoomLevel, + ParameterLast +}; + +static ParamName loadfinished[] = { + ParameterLast +}; + +/* configuration, allows nested code to access above variables */ +#include "config.h" + +void +die(const char *errstr, ...) +{ + va_list ap; + + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + exit(1); +} + +void +usage(void) +{ + die("usage: surf [-bBdDfFgGiIkKmMnNsStTvwxX]\n" + "[-a cookiepolicies ] [-c cookiefile] [-C stylefile] [-e xid]\n" + "[-r scriptfile] [-u useragent] [-z zoomlevel] [uri]\n"); +} + +void +setup(void) +{ + GIOChannel *gchanin; + GdkDisplay *gdpy; + int i, j; + + /* clean up any zombies immediately */ + sigchld(0); + if (signal(SIGHUP, sighup) == SIG_ERR) + die("Can't install SIGHUP handler"); + + if (!(dpy = XOpenDisplay(NULL))) + die("Can't open default display"); + + /* atoms */ + atoms[AtomFind] = XInternAtom(dpy, "_SURF_FIND", False); + atoms[AtomGo] = XInternAtom(dpy, "_SURF_GO", False); + atoms[AtomUri] = XInternAtom(dpy, "_SURF_URI", False); + atoms[AtomUTF8] = XInternAtom(dpy, "UTF8_STRING", False); + + gtk_init(NULL, NULL); + + gdpy = gdk_display_get_default(); + + curconfig = defconfig; + + /* dirs and files */ + cookiefile = buildfile(cookiefile); + scriptfile = buildfile(scriptfile); + certdir = buildpath(certdir); + if (curconfig[Ephemeral].val.i) + cachedir = NULL; + else + cachedir = buildpath(cachedir); + + gdkkb = gdk_seat_get_keyboard(gdk_display_get_default_seat(gdpy)); + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, spair) < 0) { + fputs("Unable to create sockets\n", stderr); + spair[0] = spair[1] = -1; + } else { + gchanin = g_io_channel_unix_new(spair[0]); + g_io_channel_set_encoding(gchanin, NULL, NULL); + g_io_channel_set_flags(gchanin, g_io_channel_get_flags(gchanin) + | G_IO_FLAG_NONBLOCK, NULL); + g_io_channel_set_close_on_unref(gchanin, TRUE); + } + + + for (i = 0; i < LENGTH(certs); ++i) { + if (!regcomp(&(certs[i].re), certs[i].regex, REG_EXTENDED)) { + certs[i].file = g_strconcat(certdir, "/", certs[i].file, + NULL); + } else { + fprintf(stderr, "Could not compile regex: %s\n", + certs[i].regex); + certs[i].regex = NULL; + } + } + + if (!stylefile) { + styledir = buildpath(styledir); + for (i = 0; i < LENGTH(styles); ++i) { + if (!regcomp(&(styles[i].re), styles[i].regex, + REG_EXTENDED)) { + styles[i].file = g_strconcat(styledir, "/", + styles[i].file, NULL); + } else { + fprintf(stderr, "Could not compile regex: %s\n", + styles[i].regex); + styles[i].regex = NULL; + } + } + g_free(styledir); + } else { + stylefile = buildfile(stylefile); + } + + for (i = 0; i < LENGTH(uriparams); ++i) { + if (regcomp(&(uriparams[i].re), uriparams[i].uri, + REG_EXTENDED)) { + fprintf(stderr, "Could not compile regex: %s\n", + uriparams[i].uri); + uriparams[i].uri = NULL; + continue; + } + + /* copy default parameters with higher priority */ + for (j = 0; j < ParameterLast; ++j) { + if (defconfig[j].prio >= uriparams[i].config[j].prio) + uriparams[i].config[j] = defconfig[j]; + } + } +} + +void +sigchld(int unused) +{ + if (signal(SIGCHLD, sigchld) == SIG_ERR) + die("Can't install SIGCHLD handler"); + while (waitpid(-1, NULL, WNOHANG) > 0) + ; +} + +void +sighup(int unused) +{ + Arg a = { .i = 0 }; + Client *c; + + for (c = clients; c; c = c->next) + reload(c, &a); +} + +char * +buildfile(const char *path) +{ + char *dname, *bname, *bpath, *fpath; + FILE *f; + + dname = g_path_get_dirname(path); + bname = g_path_get_basename(path); + + bpath = buildpath(dname); + g_free(dname); + + fpath = g_build_filename(bpath, bname, NULL); + g_free(bpath); + g_free(bname); + + if (!(f = fopen(fpath, "a"))) + die("Could not open file: %s\n", fpath); + + g_chmod(fpath, 0600); /* always */ + fclose(f); + + return fpath; +} + +static const char* +getuserhomedir(const char *user) +{ + struct passwd *pw = getpwnam(user); + + if (!pw) + die("Can't get user %s login information.\n", user); + + return pw->pw_dir; +} + +static const char* +getcurrentuserhomedir(void) +{ + const char *homedir; + const char *user; + struct passwd *pw; + + homedir = getenv("HOME"); + if (homedir) + return homedir; + + user = getenv("USER"); + if (user) + return getuserhomedir(user); + + pw = getpwuid(getuid()); + if (!pw) + die("Can't get current user home directory\n"); + + return pw->pw_dir; +} + +char * +buildpath(const char *path) +{ + char *apath, *fpath; + + if (path[0] == '~') + apath = untildepath(path); + else + apath = g_strdup(path); + + /* creating directory */ + if (g_mkdir_with_parents(apath, 0700) < 0) + die("Could not access directory: %s\n", apath); + + fpath = realpath(apath, NULL); + g_free(apath); + + return fpath; +} + +char * +untildepath(const char *path) +{ + char *apath, *name, *p; + const char *homedir; + + if (path[1] == '/' || path[1] == '\0') { + p = (char *)&path[1]; + homedir = getcurrentuserhomedir(); + } else { + if ((p = strchr(path, '/'))) + name = g_strndup(&path[1], p - (path + 1)); + else + name = g_strdup(&path[1]); + + homedir = getuserhomedir(name); + g_free(name); + } + apath = g_build_filename(homedir, p, NULL); + return apath; +} + +Client * +newclient(Client *rc) +{ + Client *c; + + if (!(c = calloc(1, sizeof(Client)))) + die("Cannot malloc!\n"); + + c->next = clients; + clients = c; + + c->progress = 100; + c->view = newview(c, rc ? rc->view : NULL); + + return c; +} + +void +loaduri(Client *c, const Arg *a) +{ + struct stat st; + char *url, *path, *apath; + const char *uri = a->v; + + if (g_strcmp0(uri, "") == 0) + return; + + for (int i = 0; i < LENGTH(aliases); i++) { + if (strcmp(aliases[i].alias, uri) == 0) { + uri = aliases[i].uri; + break; + } + } + + if (g_str_has_prefix(uri, "http://") || + g_str_has_prefix(uri, "https://") || + g_str_has_prefix(uri, "file://") || + g_str_has_prefix(uri, "webkit://") || + g_str_has_prefix(uri, "about:")) { + url = g_strdup(uri); + } else { + if (uri[0] == '~') + apath = untildepath(uri); + else + apath = (char *)uri; + if (!stat(apath, &st) && (path = realpath(apath, NULL))) { + url = g_strdup_printf("file://%s", path); + free(path); + } else { + url = g_strdup_printf("http://%s", uri); + } + if (apath != uri) + free(apath); + } + + setatom(c, AtomUri, url); + + if (strcmp(url, geturi(c)) == 0) { + reload(c, a); + } else { + webkit_web_view_load_uri(c->view, url); + updatetitle(c); + } + + g_free(url); +} + +const char * +geturi(Client *c) +{ + const char *uri; + + if (!(uri = webkit_web_view_get_uri(c->view))) + uri = "about:blank"; + return uri; +} + +void +setatom(Client *c, int a, const char *v) +{ + XChangeProperty(dpy, c->xid, + atoms[a], atoms[AtomUTF8], 8, PropModeReplace, + (unsigned char *)v, strlen(v) + 1); + XSync(dpy, False); +} + +const char * +getatom(Client *c, int a) +{ + static char buf[BUFSIZ]; + Atom adummy; + int idummy; + unsigned long ldummy; + unsigned char *p = NULL; + + XSync(dpy, False); + XGetWindowProperty(dpy, c->xid, + atoms[a], 0L, BUFSIZ, False, atoms[AtomUTF8], + &adummy, &idummy, &ldummy, &ldummy, &p); + if (p) + strncpy(buf, (char *)p, LENGTH(buf) - 1); + else + buf[0] = '\0'; + XFree(p); + + return buf; +} + +void +updatetitle(Client *c) +{ + char *title; + const char *name = c->overtitle ? c->overtitle : + c->title ? c->title : ""; + + if (curconfig[ShowIndicators].val.i) { + gettogglestats(c); + getpagestats(c); + + if (c->progress != 100) + title = g_strdup_printf("[%i%%] %s:%s | %s", + c->progress, togglestats, pagestats, name); + else + title = g_strdup_printf("%s:%s | %s", + togglestats, pagestats, name); + + gtk_window_set_title(GTK_WINDOW(c->win), title); + g_free(title); + } else { + gtk_window_set_title(GTK_WINDOW(c->win), name); + } +} + +void +gettogglestats(Client *c) +{ + togglestats[0] = cookiepolicy_set(cookiepolicy_get()); + togglestats[1] = curconfig[CaretBrowsing].val.i ? 'C' : 'c'; + togglestats[2] = curconfig[Geolocation].val.i ? 'G' : 'g'; + togglestats[3] = curconfig[DiskCache].val.i ? 'D' : 'd'; + togglestats[4] = curconfig[LoadImages].val.i ? 'I' : 'i'; + togglestats[5] = curconfig[JavaScript].val.i ? 'S' : 's'; + togglestats[6] = curconfig[Style].val.i ? 'M' : 'm'; + togglestats[8] = curconfig[Certificate].val.i ? 'X' : 'x'; + togglestats[9] = curconfig[StrictTLS].val.i ? 'T' : 't'; +} + +void +getpagestats(Client *c) +{ + if (c->https) + pagestats[0] = (c->tlserr || c->insecure) ? 'U' : 'T'; + else + pagestats[0] = '-'; + pagestats[1] = '\0'; +} + +WebKitCookieAcceptPolicy +cookiepolicy_get(void) +{ + switch (((char *)curconfig[CookiePolicies].val.v)[cookiepolicy]) { + case 'a': + return WEBKIT_COOKIE_POLICY_ACCEPT_NEVER; + case '@': + return WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY; + default: /* fallthrough */ + case 'A': + return WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS; + } +} + +char +cookiepolicy_set(const WebKitCookieAcceptPolicy p) +{ + switch (p) { + case WEBKIT_COOKIE_POLICY_ACCEPT_NEVER: + return 'a'; + case WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY: + return '@'; + default: /* fallthrough */ + case WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS: + return 'A'; + } +} + +void +seturiparameters(Client *c, const char *uri, ParamName *params) +{ + Parameter *config, *uriconfig = NULL; + int i, p; + + for (i = 0; i < LENGTH(uriparams); ++i) { + if (uriparams[i].uri && + !regexec(&(uriparams[i].re), uri, 0, NULL, 0)) { + uriconfig = uriparams[i].config; + break; + } + } + + curconfig = uriconfig ? uriconfig : defconfig; + + for (i = 0; (p = params[i]) != ParameterLast; ++i) { + switch(p) { + default: /* FALLTHROUGH */ + if (!(defconfig[p].prio < curconfig[p].prio || + defconfig[p].prio < modparams[p])) + continue; + case Certificate: + case CookiePolicies: + case Style: + setparameter(c, 0, p, &curconfig[p].val); + } + } +} + +void +setparameter(Client *c, int refresh, ParamName p, const Arg *a) +{ + GdkRGBA bgcolor = { 0 }; + + modparams[p] = curconfig[p].prio; + + switch (p) { + case AccessMicrophone: + return; /* do nothing */ + case AccessWebcam: + return; /* do nothing */ + case CaretBrowsing: + webkit_settings_set_enable_caret_browsing(c->settings, a->i); + refresh = 0; + break; + case Certificate: + if (a->i) + setcert(c, geturi(c)); + return; /* do not update */ + case CookiePolicies: + webkit_cookie_manager_set_accept_policy( + webkit_web_context_get_cookie_manager(c->context), + cookiepolicy_get()); + refresh = 0; + break; + case DarkMode: + g_object_set(gtk_settings_get_default(), + "gtk-application-prefer-dark-theme", a->i, NULL); + return; + case DiskCache: + webkit_web_context_set_cache_model(c->context, a->i ? + WEBKIT_CACHE_MODEL_WEB_BROWSER : + WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER); + return; /* do not update */ + case DefaultCharset: + webkit_settings_set_default_charset(c->settings, a->v); + return; /* do not update */ + case DNSPrefetch: + webkit_settings_set_enable_dns_prefetching(c->settings, a->i); + return; /* do not update */ + case FileURLsCrossAccess: + webkit_settings_set_allow_file_access_from_file_urls( + c->settings, a->i); + webkit_settings_set_allow_universal_access_from_file_urls( + c->settings, a->i); + return; /* do not update */ + case FontSize: + webkit_settings_set_default_font_size(c->settings, a->i); + return; /* do not update */ + case Geolocation: + refresh = 0; + break; + case HideBackground: + if (a->i) + webkit_web_view_set_background_color(c->view, &bgcolor); + return; /* do not update */ + case Inspector: + webkit_settings_set_enable_developer_extras(c->settings, a->i); + return; /* do not update */ + case JavaScript: + webkit_settings_set_enable_javascript(c->settings, a->i); + break; + case KioskMode: + return; /* do nothing */ + case LoadImages: + webkit_settings_set_auto_load_images(c->settings, a->i); + break; + case MediaManualPlay: + webkit_settings_set_media_playback_requires_user_gesture( + c->settings, a->i); + break; + case PreferredLanguages: + return; /* do nothing */ + case RunInFullscreen: + return; /* do nothing */ + case ScrollBars: + /* Disabled until we write some WebKitWebExtension for + * manipulating the DOM directly. + enablescrollbars = !enablescrollbars; + evalscript(c, "document.documentElement.style.overflow = '%s'", + enablescrollbars ? "auto" : "hidden"); + */ + return; /* do not update */ + case ShowIndicators: + break; + case SmoothScrolling: + webkit_settings_set_enable_smooth_scrolling(c->settings, a->i); + return; /* do not update */ + case SiteQuirks: + webkit_settings_set_enable_site_specific_quirks( + c->settings, a->i); + break; + case SpellChecking: + webkit_web_context_set_spell_checking_enabled( + c->context, a->i); + return; /* do not update */ + case SpellLanguages: + return; /* do nothing */ + case StrictTLS: + webkit_website_data_manager_set_tls_errors_policy( + webkit_web_view_get_website_data_manager(c->view), a->i ? + WEBKIT_TLS_ERRORS_POLICY_FAIL : + WEBKIT_TLS_ERRORS_POLICY_IGNORE); + break; + case Style: + webkit_user_content_manager_remove_all_style_sheets( + webkit_web_view_get_user_content_manager(c->view)); + if (a->i) + setstyle(c, getstyle(geturi(c))); + refresh = 0; + break; + case WebGL: + webkit_settings_set_enable_webgl(c->settings, a->i); + break; + case ZoomLevel: + webkit_web_view_set_zoom_level(c->view, a->f); + return; /* do not update */ + default: + return; /* do nothing */ + } + + updatetitle(c); + if (refresh) + reload(c, a); +} + +const char * +getcert(const char *uri) +{ + int i; + + for (i = 0; i < LENGTH(certs); ++i) { + if (certs[i].regex && + !regexec(&(certs[i].re), uri, 0, NULL, 0)) + return certs[i].file; + } + + return NULL; +} + +void +setcert(Client *c, const char *uri) +{ + const char *file = getcert(uri); + char *host; + GTlsCertificate *cert; + + if (!file) + return; + + if (!(cert = g_tls_certificate_new_from_file(file, NULL))) { + fprintf(stderr, "Could not read certificate file: %s\n", file); + return; + } + + if ((uri = strstr(uri, "https://"))) { + uri += sizeof("https://") - 1; + host = g_strndup(uri, strchr(uri, '/') - uri); + webkit_web_context_allow_tls_certificate_for_host(c->context, + cert, host); + g_free(host); + } + + g_object_unref(cert); + +} + +const char * +getstyle(const char *uri) +{ + int i; + + if (stylefile) + return stylefile; + + for (i = 0; i < LENGTH(styles); ++i) { + if (styles[i].regex && + !regexec(&(styles[i].re), uri, 0, NULL, 0)) + return styles[i].file; + } + + return ""; +} + +void +setstyle(Client *c, const char *file) +{ + gchar *style; + + if (!g_file_get_contents(file, &style, NULL, NULL)) { + fprintf(stderr, "Could not read style file: %s\n", file); + return; + } + + webkit_user_content_manager_add_style_sheet( + webkit_web_view_get_user_content_manager(c->view), + webkit_user_style_sheet_new(style, + WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, + WEBKIT_USER_STYLE_LEVEL_USER, + NULL, NULL)); + + g_free(style); +} + +void +runscript(Client *c) +{ + gchar *script; + gsize l; + + if (g_file_get_contents(scriptfile, &script, &l, NULL) && l) + evalscript(c, "%s", script); + g_free(script); +} + +void +evalscript(Client *c, const char *jsstr, ...) +{ + va_list ap; + gchar *script; + + va_start(ap, jsstr); + script = g_strdup_vprintf(jsstr, ap); + va_end(ap); + + webkit_web_view_evaluate_javascript(c->view, script, -1, + NULL, NULL, NULL, NULL, NULL); + g_free(script); +} + +void +updatewinid(Client *c) +{ + snprintf(winid, LENGTH(winid), "%lu", c->xid); +} + +void +handleplumb(Client *c, const char *uri) +{ + Arg a = (Arg)PLUMB(uri); + spawn(c, &a); +} + +void +newwindow(Client *c, const Arg *a, int noembed) +{ + int i = 0; + char tmp[64]; + const char *cmd[29], *uri; + const Arg arg = { .v = cmd }; + + cmd[i++] = argv0; + cmd[i++] = "-a"; + cmd[i++] = curconfig[CookiePolicies].val.v; + cmd[i++] = curconfig[ScrollBars].val.i ? "-B" : "-b"; + if (cookiefile && g_strcmp0(cookiefile, "")) { + cmd[i++] = "-c"; + cmd[i++] = cookiefile; + } + if (stylefile && g_strcmp0(stylefile, "")) { + cmd[i++] = "-C"; + cmd[i++] = stylefile; + } + cmd[i++] = curconfig[DiskCache].val.i ? "-D" : "-d"; + if (embed && !noembed) { + cmd[i++] = "-e"; + snprintf(tmp, LENGTH(tmp), "%lu", embed); + cmd[i++] = tmp; + } + cmd[i++] = curconfig[RunInFullscreen].val.i ? "-F" : "-f" ; + cmd[i++] = curconfig[Geolocation].val.i ? "-G" : "-g" ; + cmd[i++] = curconfig[LoadImages].val.i ? "-I" : "-i" ; + cmd[i++] = curconfig[KioskMode].val.i ? "-K" : "-k" ; + cmd[i++] = curconfig[Style].val.i ? "-M" : "-m" ; + cmd[i++] = curconfig[Inspector].val.i ? "-N" : "-n" ; + if (scriptfile && g_strcmp0(scriptfile, "")) { + cmd[i++] = "-r"; + cmd[i++] = scriptfile; + } + cmd[i++] = curconfig[JavaScript].val.i ? "-S" : "-s"; + cmd[i++] = curconfig[StrictTLS].val.i ? "-T" : "-t"; + if (fulluseragent && g_strcmp0(fulluseragent, "")) { + cmd[i++] = "-u"; + cmd[i++] = fulluseragent; + } + if (showxid) + cmd[i++] = "-w"; + cmd[i++] = curconfig[Certificate].val.i ? "-X" : "-x" ; + /* do not keep zoom level */ + cmd[i++] = "--"; + if ((uri = a->v)) + cmd[i++] = uri; + cmd[i] = NULL; + + spawn(c, &arg); +} + +void +spawn(Client *c, const Arg *a) +{ + if (fork() == 0) { + if (dpy) + close(ConnectionNumber(dpy)); + close(spair[0]); + close(spair[1]); + setsid(); + execvp(((char **)a->v)[0], (char **)a->v); + fprintf(stderr, "%s: execvp %s", argv0, ((char **)a->v)[0]); + perror(" failed"); + exit(1); + } +} + +void +destroyclient(Client *c) +{ + Client *p; + + webkit_web_view_stop_loading(c->view); + /* Not needed, has already been called + gtk_widget_destroy(c->win); + */ + + for (p = clients; p && p->next != c; p = p->next) + ; + if (p) + p->next = c->next; + else + clients = c->next; + free(c); +} + +void +cleanup(void) +{ + while (clients) + destroyclient(clients); + + close(spair[0]); + close(spair[1]); + g_free(cookiefile); + g_free(scriptfile); + g_free(stylefile); + g_free(cachedir); + XCloseDisplay(dpy); +} + +WebKitWebView * +newview(Client *c, WebKitWebView *rv) +{ + WebKitWebView *v; + WebKitSettings *settings; + WebKitWebContext *context; + WebKitCookieManager *cookiemanager; + WebKitUserContentManager *contentmanager; + + /* Webview */ + if (rv) { + v = WEBKIT_WEB_VIEW(webkit_web_view_new_with_related_view(rv)); + context = webkit_web_view_get_context(v); + settings = webkit_web_view_get_settings(v); + } else { + settings = webkit_settings_new_with_settings( + "allow-file-access-from-file-urls", curconfig[FileURLsCrossAccess].val.i, + "allow-universal-access-from-file-urls", curconfig[FileURLsCrossAccess].val.i, + "auto-load-images", curconfig[LoadImages].val.i, + "default-charset", curconfig[DefaultCharset].val.v, + "default-font-size", curconfig[FontSize].val.i, + "enable-caret-browsing", curconfig[CaretBrowsing].val.i, + "enable-developer-extras", curconfig[Inspector].val.i, + "enable-dns-prefetching", curconfig[DNSPrefetch].val.i, + "enable-html5-database", curconfig[DiskCache].val.i, + "enable-html5-local-storage", curconfig[DiskCache].val.i, + "enable-javascript", curconfig[JavaScript].val.i, + "enable-site-specific-quirks", curconfig[SiteQuirks].val.i, + "enable-smooth-scrolling", curconfig[SmoothScrolling].val.i, + "enable-webgl", curconfig[WebGL].val.i, + "media-playback-requires-user-gesture", curconfig[MediaManualPlay].val.i, + NULL); +/* For more interesting settings, have a look at + * http://webkitgtk.org/reference/webkit2gtk/stable/WebKitSettings.html */ + + if (strcmp(fulluseragent, "")) { + webkit_settings_set_user_agent(settings, fulluseragent); + } else if (surfuseragent) { + webkit_settings_set_user_agent_with_application_details( + settings, "Surf", VERSION); + } + useragent = webkit_settings_get_user_agent(settings); + + contentmanager = webkit_user_content_manager_new(); + + if (curconfig[Ephemeral].val.i) { + context = webkit_web_context_new_ephemeral(); + } else { + context = webkit_web_context_new_with_website_data_manager( + webkit_website_data_manager_new( + "base-cache-directory", cachedir, + "base-data-directory", cachedir, + NULL)); + } + + cookiemanager = webkit_web_context_get_cookie_manager(context); + + /* TLS */ + webkit_website_data_manager_set_tls_errors_policy( + webkit_web_context_get_website_data_manager(context), + curconfig[StrictTLS].val.i ? WEBKIT_TLS_ERRORS_POLICY_FAIL : + WEBKIT_TLS_ERRORS_POLICY_IGNORE); + /* disk cache */ + webkit_web_context_set_cache_model(context, + curconfig[DiskCache].val.i ? WEBKIT_CACHE_MODEL_WEB_BROWSER : + WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER); + + /* Currently only works with text file to be compatible with curl */ + if (!curconfig[Ephemeral].val.i) + webkit_cookie_manager_set_persistent_storage(cookiemanager, + cookiefile, WEBKIT_COOKIE_PERSISTENT_STORAGE_TEXT); + /* cookie policy */ + webkit_cookie_manager_set_accept_policy(cookiemanager, + cookiepolicy_get()); + /* languages */ + webkit_web_context_set_preferred_languages(context, + curconfig[PreferredLanguages].val.v); + webkit_web_context_set_spell_checking_languages(context, + curconfig[SpellLanguages].val.v); + webkit_web_context_set_spell_checking_enabled(context, + curconfig[SpellChecking].val.i); + + g_signal_connect(G_OBJECT(context), "download-started", + G_CALLBACK(downloadstarted), c); + g_signal_connect(G_OBJECT(context), "initialize-web-extensions", + G_CALLBACK(initwebextensions), c); + + v = g_object_new(WEBKIT_TYPE_WEB_VIEW, + "settings", settings, + "user-content-manager", contentmanager, + "web-context", context, + NULL); + } + + g_signal_connect(G_OBJECT(v), "notify::estimated-load-progress", + G_CALLBACK(progresschanged), c); + g_signal_connect(G_OBJECT(v), "notify::title", + G_CALLBACK(titlechanged), c); + g_signal_connect(G_OBJECT(v), "button-release-event", + G_CALLBACK(buttonreleased), c); + g_signal_connect(G_OBJECT(v), "close", + G_CALLBACK(closeview), c); + g_signal_connect(G_OBJECT(v), "create", + G_CALLBACK(createview), c); + g_signal_connect(G_OBJECT(v), "decide-policy", + G_CALLBACK(decidepolicy), c); + g_signal_connect(G_OBJECT(v), "insecure-content-detected", + G_CALLBACK(insecurecontent), c); + g_signal_connect(G_OBJECT(v), "load-failed-with-tls-errors", + G_CALLBACK(loadfailedtls), c); + g_signal_connect(G_OBJECT(v), "load-changed", + G_CALLBACK(loadchanged), c); + g_signal_connect(G_OBJECT(v), "mouse-target-changed", + G_CALLBACK(mousetargetchanged), c); + g_signal_connect(G_OBJECT(v), "permission-request", + G_CALLBACK(permissionrequested), c); + g_signal_connect(G_OBJECT(v), "ready-to-show", + G_CALLBACK(showview), c); + g_signal_connect(G_OBJECT(v), "user-message-received", + G_CALLBACK(viewusrmsgrcv), c); + g_signal_connect(G_OBJECT(v), "web-process-terminated", + G_CALLBACK(webprocessterminated), c); + + c->context = context; + c->settings = settings; + + setparameter(c, 0, DarkMode, &curconfig[DarkMode].val); + + return v; +} + +void +initwebextensions(WebKitWebContext *wc, Client *c) +{ + webkit_web_context_set_web_extensions_directory(wc, WEBEXTDIR); +} + +GtkWidget * +createview(WebKitWebView *v, WebKitNavigationAction *a, Client *c) +{ + Client *n; + + switch (webkit_navigation_action_get_navigation_type(a)) { + case WEBKIT_NAVIGATION_TYPE_OTHER: /* fallthrough */ + /* + * popup windows of type “other” are almost always triggered + * by user gesture, so inverse the logic here + */ +/* instead of this, compare destination uri to mouse-over uri for validating window */ + if (webkit_navigation_action_is_user_gesture(a)) + return NULL; + case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_RELOAD: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED: + n = newclient(c); + break; + default: + return NULL; + } + + return GTK_WIDGET(n->view); +} + +gboolean +buttonreleased(GtkWidget *w, GdkEvent *e, Client *c) +{ + WebKitHitTestResultContext element; + int i; + + element = webkit_hit_test_result_get_context(c->mousepos); + + for (i = 0; i < LENGTH(buttons); ++i) { + if (element & buttons[i].target && + e->button.button == buttons[i].button && + CLEANMASK(e->button.state) == CLEANMASK(buttons[i].mask) && + buttons[i].func) { + buttons[i].func(c, &buttons[i].arg, c->mousepos); + return buttons[i].stopevent; + } + } + + return FALSE; +} + +GdkFilterReturn +processx(GdkXEvent *e, GdkEvent *event, gpointer d) +{ + Client *c = (Client *)d; + XPropertyEvent *ev; + Arg a; + + if (((XEvent *)e)->type == PropertyNotify) { + ev = &((XEvent *)e)->xproperty; + if (ev->state == PropertyNewValue) { + if (ev->atom == atoms[AtomFind]) { + find(c, NULL); + + return GDK_FILTER_REMOVE; + } else if (ev->atom == atoms[AtomGo]) { + a.v = getatom(c, AtomGo); + loaduri(c, &a); + + return GDK_FILTER_REMOVE; + } + } + } + return GDK_FILTER_CONTINUE; +} + +gboolean +winevent(GtkWidget *w, GdkEvent *e, Client *c) +{ + int i; + + switch (e->type) { + case GDK_ENTER_NOTIFY: + c->overtitle = c->targeturi; + updatetitle(c); + break; + case GDK_KEY_PRESS: + if (!curconfig[KioskMode].val.i) { + for (i = 0; i < LENGTH(keys); ++i) { + if (gdk_keyval_to_lower(e->key.keyval) == + keys[i].keyval && + CLEANMASK(e->key.state) == keys[i].mod && + keys[i].func) { + updatewinid(c); + keys[i].func(c, &(keys[i].arg)); + return TRUE; + } + } + } + case GDK_LEAVE_NOTIFY: + c->overtitle = NULL; + updatetitle(c); + break; + case GDK_WINDOW_STATE: + if (e->window_state.changed_mask == + GDK_WINDOW_STATE_FULLSCREEN) + c->fullscreen = e->window_state.new_window_state & + GDK_WINDOW_STATE_FULLSCREEN; + break; + default: + break; + } + + return FALSE; +} + +void +showview(WebKitWebView *v, Client *c) +{ + GdkRGBA bgcolor = { 0 }; + GdkWindow *gwin; + + c->finder = webkit_web_view_get_find_controller(c->view); + c->inspector = webkit_web_view_get_inspector(c->view); + + c->pageid = webkit_web_view_get_page_id(c->view); + c->win = createwindow(c); + + gtk_container_add(GTK_CONTAINER(c->win), GTK_WIDGET(c->view)); + gtk_widget_show_all(c->win); + gtk_widget_grab_focus(GTK_WIDGET(c->view)); + + gwin = gtk_widget_get_window(GTK_WIDGET(c->win)); + c->xid = gdk_x11_window_get_xid(gwin); + updatewinid(c); + if (showxid) { + gdk_display_sync(gtk_widget_get_display(c->win)); + puts(winid); + fflush(stdout); + } + + if (curconfig[HideBackground].val.i) + webkit_web_view_set_background_color(c->view, &bgcolor); + + if (!curconfig[KioskMode].val.i) { + gdk_window_set_events(gwin, GDK_ALL_EVENTS_MASK); + gdk_window_add_filter(gwin, processx, c); + } + + if (curconfig[RunInFullscreen].val.i) + togglefullscreen(c, NULL); + + if (curconfig[ZoomLevel].val.f != 1.0) + webkit_web_view_set_zoom_level(c->view, + curconfig[ZoomLevel].val.f); + + setatom(c, AtomFind, ""); + setatom(c, AtomUri, "about:blank"); +} + +GtkWidget * +createwindow(Client *c) +{ + char *wmstr; + GtkWidget *w; + + if (embed) { + w = gtk_plug_new(embed); + } else { + w = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + wmstr = g_path_get_basename(argv0); + gtk_window_set_wmclass(GTK_WINDOW(w), wmstr, "Surf"); + g_free(wmstr); + + wmstr = g_strdup_printf("%s[%"PRIu64"]", "Surf", c->pageid); + gtk_window_set_role(GTK_WINDOW(w), wmstr); + g_free(wmstr); + + gtk_window_set_default_size(GTK_WINDOW(w), winsize[0], winsize[1]); + } + + g_signal_connect(G_OBJECT(w), "destroy", + G_CALLBACK(destroywin), c); + g_signal_connect(G_OBJECT(w), "enter-notify-event", + G_CALLBACK(winevent), c); + g_signal_connect(G_OBJECT(w), "key-press-event", + G_CALLBACK(winevent), c); + g_signal_connect(G_OBJECT(w), "leave-notify-event", + G_CALLBACK(winevent), c); + g_signal_connect(G_OBJECT(w), "window-state-event", + G_CALLBACK(winevent), c); + + return w; +} + +gboolean +loadfailedtls(WebKitWebView *v, gchar *uri, GTlsCertificate *cert, + GTlsCertificateFlags err, Client *c) +{ + GString *errmsg = g_string_new(NULL); + gchar *html, *pem; + + c->failedcert = g_object_ref(cert); + c->tlserr = err; + c->errorpage = 1; + + if (err & G_TLS_CERTIFICATE_UNKNOWN_CA) + g_string_append(errmsg, + "The signing certificate authority is not known.
"); + if (err & G_TLS_CERTIFICATE_BAD_IDENTITY) + g_string_append(errmsg, + "The certificate does not match the expected identity " + "of the site that it was retrieved from.
"); + if (err & G_TLS_CERTIFICATE_NOT_ACTIVATED) + g_string_append(errmsg, + "The certificate's activation time " + "is still in the future.
"); + if (err & G_TLS_CERTIFICATE_EXPIRED) + g_string_append(errmsg, "The certificate has expired.
"); + if (err & G_TLS_CERTIFICATE_REVOKED) + g_string_append(errmsg, + "The certificate has been revoked according to " + "the GTlsConnection's certificate revocation list.
"); + if (err & G_TLS_CERTIFICATE_INSECURE) + g_string_append(errmsg, + "The certificate's algorithm is considered insecure.
"); + if (err & G_TLS_CERTIFICATE_GENERIC_ERROR) + g_string_append(errmsg, + "Some error occurred validating the certificate.
"); + + g_object_get(cert, "certificate-pem", &pem, NULL); + html = g_strdup_printf("

Could not validate TLS for “%s”
%s

" + "

You can inspect the following certificate " + "with Ctrl-t (default keybinding).

" + "

%s

", uri, errmsg->str, pem); + g_free(pem); + g_string_free(errmsg, TRUE); + + webkit_web_view_load_alternate_html(c->view, html, uri, NULL); + g_free(html); + + return TRUE; +} + +void +loadchanged(WebKitWebView *v, WebKitLoadEvent e, Client *c) +{ + const char *uri = geturi(c); + + switch (e) { + case WEBKIT_LOAD_STARTED: + setatom(c, AtomUri, uri); + c->title = uri; + c->https = c->insecure = 0; + seturiparameters(c, uri, loadtransient); + if (c->errorpage) + c->errorpage = 0; + else + g_clear_object(&c->failedcert); + break; + case WEBKIT_LOAD_REDIRECTED: + setatom(c, AtomUri, uri); + c->title = uri; + seturiparameters(c, uri, loadtransient); + break; + case WEBKIT_LOAD_COMMITTED: + setatom(c, AtomUri, uri); + c->title = uri; + seturiparameters(c, uri, loadcommitted); + c->https = webkit_web_view_get_tls_info(c->view, &c->cert, + &c->tlserr); + break; + case WEBKIT_LOAD_FINISHED: + seturiparameters(c, uri, loadfinished); + /* Disabled until we write some WebKitWebExtension for + * manipulating the DOM directly. + evalscript(c, "document.documentElement.style.overflow = '%s'", + enablescrollbars ? "auto" : "hidden"); + */ + runscript(c); + break; + } + updatetitle(c); +} + +void +progresschanged(WebKitWebView *v, GParamSpec *ps, Client *c) +{ + c->progress = webkit_web_view_get_estimated_load_progress(c->view) * + 100; + updatetitle(c); +} + +void +titlechanged(WebKitWebView *view, GParamSpec *ps, Client *c) +{ + c->title = webkit_web_view_get_title(c->view); + updatetitle(c); +} + +gboolean +viewusrmsgrcv(WebKitWebView *v, WebKitUserMessage *m, gpointer unused) +{ + WebKitUserMessage *r; + GUnixFDList *gfd; + const char *name; + + name = webkit_user_message_get_name(m); + if (strcmp(name, "page-created") != 0) { + fprintf(stderr, "surf: Unknown UserMessage: %s\n", name); + return TRUE; + } + + if (spair[1] < 0) + return TRUE; + + gfd = g_unix_fd_list_new_from_array(&spair[1], 1); + r = webkit_user_message_new_with_fd_list("surf-pipe", NULL, gfd); + + webkit_user_message_send_reply(m, r); + + return TRUE; +} + +void +mousetargetchanged(WebKitWebView *v, WebKitHitTestResult *h, guint modifiers, + Client *c) +{ + WebKitHitTestResultContext hc = webkit_hit_test_result_get_context(h); + + /* Keep the hit test to know where is the pointer on the next click */ + c->mousepos = h; + + if (hc & OnLink) + c->targeturi = webkit_hit_test_result_get_link_uri(h); + else if (hc & OnImg) + c->targeturi = webkit_hit_test_result_get_image_uri(h); + else if (hc & OnMedia) + c->targeturi = webkit_hit_test_result_get_media_uri(h); + else + c->targeturi = NULL; + + c->overtitle = c->targeturi; + updatetitle(c); +} + +gboolean +permissionrequested(WebKitWebView *v, WebKitPermissionRequest *r, Client *c) +{ + ParamName param = ParameterLast; + + if (WEBKIT_IS_GEOLOCATION_PERMISSION_REQUEST(r)) { + param = Geolocation; + } else if (WEBKIT_IS_USER_MEDIA_PERMISSION_REQUEST(r)) { + if (webkit_user_media_permission_is_for_audio_device( + WEBKIT_USER_MEDIA_PERMISSION_REQUEST(r))) + param = AccessMicrophone; + else if (webkit_user_media_permission_is_for_video_device( + WEBKIT_USER_MEDIA_PERMISSION_REQUEST(r))) + param = AccessWebcam; + } else { + return FALSE; + } + + if (curconfig[param].val.i) + webkit_permission_request_allow(r); + else + webkit_permission_request_deny(r); + + return TRUE; +} + +gboolean +decidepolicy(WebKitWebView *v, WebKitPolicyDecision *d, + WebKitPolicyDecisionType dt, Client *c) +{ + switch (dt) { + case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION: + decidenavigation(d, c); + break; + case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION: + decidenewwindow(d, c); + break; + case WEBKIT_POLICY_DECISION_TYPE_RESPONSE: + decideresource(d, c); + break; + default: + webkit_policy_decision_ignore(d); + break; + } + return TRUE; +} + +void +decidenavigation(WebKitPolicyDecision *d, Client *c) +{ + WebKitNavigationAction *a = + webkit_navigation_policy_decision_get_navigation_action( + WEBKIT_NAVIGATION_POLICY_DECISION(d)); + + switch (webkit_navigation_action_get_navigation_type(a)) { + case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_RELOAD: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_OTHER: /* fallthrough */ + default: + /* Do not navigate to links with a "_blank" target (popup) */ + if (webkit_navigation_action_get_frame_name(a)) { + webkit_policy_decision_ignore(d); + } else { + /* Filter out navigation to different domain ? */ + /* get action→urirequest, copy and load in new window+view + * on Ctrl+Click ? */ + webkit_policy_decision_use(d); + } + break; + } +} + +void +decidenewwindow(WebKitPolicyDecision *d, Client *c) +{ + Arg arg; + WebKitNavigationAction *a = + webkit_navigation_policy_decision_get_navigation_action( + WEBKIT_NAVIGATION_POLICY_DECISION(d)); + + + switch (webkit_navigation_action_get_navigation_type(a)) { + case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_RELOAD: /* fallthrough */ + case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED: + /* Filter domains here */ +/* If the value of “mouse-button” is not 0, then the navigation was triggered by a mouse event. + * test for link clicked but no button ? */ + arg.v = webkit_uri_request_get_uri( + webkit_navigation_action_get_request(a)); + newwindow(c, &arg, 0); + break; + case WEBKIT_NAVIGATION_TYPE_OTHER: /* fallthrough */ + default: + break; + } + + webkit_policy_decision_ignore(d); +} + +void +decideresource(WebKitPolicyDecision *d, Client *c) +{ + int i, isascii = 1; + WebKitResponsePolicyDecision *r = WEBKIT_RESPONSE_POLICY_DECISION(d); + WebKitURIResponse *res = + webkit_response_policy_decision_get_response(r); + const gchar *uri = webkit_uri_response_get_uri(res); + + if (g_str_has_suffix(uri, "/favicon.ico")) { + webkit_policy_decision_ignore(d); + return; + } + + if (!g_str_has_prefix(uri, "http://") + && !g_str_has_prefix(uri, "https://") + && !g_str_has_prefix(uri, "about:") + && !g_str_has_prefix(uri, "file://") + && !g_str_has_prefix(uri, "webkit://") + && !g_str_has_prefix(uri, "data:") + && !g_str_has_prefix(uri, "blob:") + && strlen(uri) > 0) { + for (i = 0; i < strlen(uri); i++) { + if (!g_ascii_isprint(uri[i])) { + isascii = 0; + break; + } + } + if (isascii) { + handleplumb(c, uri); + webkit_policy_decision_ignore(d); + return; + } + } + + if (webkit_response_policy_decision_is_mime_type_supported(r)) { + webkit_policy_decision_use(d); + } else { + webkit_policy_decision_ignore(d); + download(c, res); + } +} + +void +insecurecontent(WebKitWebView *v, WebKitInsecureContentEvent e, Client *c) +{ + c->insecure = 1; +} + +void +downloadstarted(WebKitWebContext *wc, WebKitDownload *d, Client *c) +{ + g_signal_connect(G_OBJECT(d), "notify::response", + G_CALLBACK(responsereceived), c); +} + +void +responsereceived(WebKitDownload *d, GParamSpec *ps, Client *c) +{ + download(c, webkit_download_get_response(d)); + webkit_download_cancel(d); +} + +void +download(Client *c, WebKitURIResponse *r) +{ + Arg a = (Arg)DOWNLOAD(webkit_uri_response_get_uri(r), geturi(c)); + spawn(c, &a); +} + +void +webprocessterminated(WebKitWebView *v, WebKitWebProcessTerminationReason r, + Client *c) +{ + fprintf(stderr, "web process terminated: %s\n", + r == WEBKIT_WEB_PROCESS_CRASHED ? "crashed" : "no memory"); + closeview(v, c); +} + +void +closeview(WebKitWebView *v, Client *c) +{ + gtk_widget_destroy(c->win); +} + +void +destroywin(GtkWidget* w, Client *c) +{ + destroyclient(c); + if (!clients) + gtk_main_quit(); +} + +void +pasteuri(GtkClipboard *clipboard, const char *text, gpointer d) +{ + Arg a = {.v = text }; + if (text) + loaduri((Client *) d, &a); +} + +void +reload(Client *c, const Arg *a) +{ + if (a->i) + webkit_web_view_reload_bypass_cache(c->view); + else + webkit_web_view_reload(c->view); +} + +void +print(Client *c, const Arg *a) +{ + webkit_print_operation_run_dialog(webkit_print_operation_new(c->view), + GTK_WINDOW(c->win)); +} + +void +showcert(Client *c, const Arg *a) +{ + GTlsCertificate *cert = c->failedcert ? c->failedcert : c->cert; + GcrCertificate *gcrt; + GByteArray *crt; + GtkWidget *win; + GcrCertificateWidget *wcert; + + if (!cert) + return; + + g_object_get(cert, "certificate", &crt, NULL); + gcrt = gcr_simple_certificate_new(crt->data, crt->len); + g_byte_array_unref(crt); + + win = gtk_window_new(GTK_WINDOW_TOPLEVEL); + wcert = gcr_certificate_widget_new(gcrt); + g_object_unref(gcrt); + + gtk_container_add(GTK_CONTAINER(win), GTK_WIDGET(wcert)); + gtk_widget_show_all(win); +} + +void +clipboard(Client *c, const Arg *a) +{ + if (a->i) { /* load clipboard uri */ + gtk_clipboard_request_text(gtk_clipboard_get( + GDK_SELECTION_PRIMARY), + pasteuri, c); + } else { /* copy uri */ + gtk_clipboard_set_text(gtk_clipboard_get( + GDK_SELECTION_PRIMARY), c->targeturi + ? c->targeturi : geturi(c), -1); + } +} + +void +zoom(Client *c, const Arg *a) +{ + if (a->i > 0) + webkit_web_view_set_zoom_level(c->view, + curconfig[ZoomLevel].val.f + 0.1); + else if (a->i < 0) + webkit_web_view_set_zoom_level(c->view, + curconfig[ZoomLevel].val.f - 0.1); + else + webkit_web_view_set_zoom_level(c->view, 1.0); + + curconfig[ZoomLevel].val.f = webkit_web_view_get_zoom_level(c->view); +} + +static void +msgext(Client *c, char type, const Arg *a) +{ + static unsigned char msg[MSGBUFSZ]; + int ret; + + if (spair[0] < 0) + return; + + ret = snprintf(msg, sizeof(msg), "%c%c%c", + (unsigned char)c->pageid, type, (signed char)a->i); + if (ret >= sizeof(msg)) { + fprintf(stderr, "surf: message too long: %d\n", ret); + return; + } + + if (send(spair[0], msg, ret, 0) != ret) + fprintf(stderr, "surf: error sending: %hhu/%c/%d (%d)\n", + (unsigned char)c->pageid, type, a->i, ret); +} + +void +scrollv(Client *c, const Arg *a) +{ + msgext(c, 'v', a); +} + +void +scrollh(Client *c, const Arg *a) +{ + msgext(c, 'h', a); +} + +void +navigate(Client *c, const Arg *a) +{ + if (a->i < 0) + webkit_web_view_go_back(c->view); + else if (a->i > 0) + webkit_web_view_go_forward(c->view); +} + +void +stop(Client *c, const Arg *a) +{ + webkit_web_view_stop_loading(c->view); +} + +void +toggle(Client *c, const Arg *a) +{ + curconfig[a->i].val.i ^= 1; + setparameter(c, 1, (ParamName)a->i, &curconfig[a->i].val); +} + +void +togglefullscreen(Client *c, const Arg *a) +{ + /* toggling value is handled in winevent() */ + if (c->fullscreen) + gtk_window_unfullscreen(GTK_WINDOW(c->win)); + else + gtk_window_fullscreen(GTK_WINDOW(c->win)); +} + +void +togglecookiepolicy(Client *c, const Arg *a) +{ + ++cookiepolicy; + cookiepolicy %= strlen(curconfig[CookiePolicies].val.v); + + setparameter(c, 0, CookiePolicies, NULL); +} + +void +toggleinspector(Client *c, const Arg *a) +{ + if (webkit_web_inspector_is_attached(c->inspector)) + webkit_web_inspector_close(c->inspector); + else if (curconfig[Inspector].val.i) + webkit_web_inspector_show(c->inspector); +} + +void +find(Client *c, const Arg *a) +{ + const char *s, *f; + + if (a && a->i) { + if (a->i > 0) + webkit_find_controller_search_next(c->finder); + else + webkit_find_controller_search_previous(c->finder); + } else { + s = getatom(c, AtomFind); + f = webkit_find_controller_get_search_text(c->finder); + + if (g_strcmp0(f, s) == 0) /* reset search */ + webkit_find_controller_search(c->finder, "", findopts, + G_MAXUINT); + + webkit_find_controller_search(c->finder, s, findopts, + G_MAXUINT); + + if (strcmp(s, "") == 0) + webkit_find_controller_search_finish(c->finder); + } +} + +void +clicknavigate(Client *c, const Arg *a, WebKitHitTestResult *h) +{ + navigate(c, a); +} + +void +clicknewwindow(Client *c, const Arg *a, WebKitHitTestResult *h) +{ + Arg arg; + + arg.v = webkit_hit_test_result_get_link_uri(h); + newwindow(c, &arg, a->i); +} + +void +clickexternplayer(Client *c, const Arg *a, WebKitHitTestResult *h) +{ + Arg arg; + + arg = (Arg)VIDEOPLAY(webkit_hit_test_result_get_media_uri(h)); + spawn(c, &arg); +} + +int +main(int argc, char *argv[]) +{ + Arg arg; + Client *c; + + memset(&arg, 0, sizeof(arg)); + + /* command line args */ + ARGBEGIN { + case 'a': + defconfig[CookiePolicies].val.v = EARGF(usage()); + defconfig[CookiePolicies].prio = 2; + break; + case 'b': + defconfig[ScrollBars].val.i = 0; + defconfig[ScrollBars].prio = 2; + break; + case 'B': + defconfig[ScrollBars].val.i = 1; + defconfig[ScrollBars].prio = 2; + break; + case 'c': + cookiefile = EARGF(usage()); + break; + case 'C': + stylefile = EARGF(usage()); + break; + case 'd': + defconfig[DiskCache].val.i = 0; + defconfig[DiskCache].prio = 2; + break; + case 'D': + defconfig[DiskCache].val.i = 1; + defconfig[DiskCache].prio = 2; + break; + case 'e': + embed = strtol(EARGF(usage()), NULL, 0); + break; + case 'f': + defconfig[RunInFullscreen].val.i = 0; + defconfig[RunInFullscreen].prio = 2; + break; + case 'F': + defconfig[RunInFullscreen].val.i = 1; + defconfig[RunInFullscreen].prio = 2; + break; + case 'g': + defconfig[Geolocation].val.i = 0; + defconfig[Geolocation].prio = 2; + break; + case 'G': + defconfig[Geolocation].val.i = 1; + defconfig[Geolocation].prio = 2; + break; + case 'i': + defconfig[LoadImages].val.i = 0; + defconfig[LoadImages].prio = 2; + break; + case 'I': + defconfig[LoadImages].val.i = 1; + defconfig[LoadImages].prio = 2; + break; + case 'k': + defconfig[KioskMode].val.i = 0; + defconfig[KioskMode].prio = 2; + break; + case 'K': + defconfig[KioskMode].val.i = 1; + defconfig[KioskMode].prio = 2; + break; + case 'm': + defconfig[Style].val.i = 0; + defconfig[Style].prio = 2; + break; + case 'M': + defconfig[Style].val.i = 1; + defconfig[Style].prio = 2; + break; + case 'n': + defconfig[Inspector].val.i = 0; + defconfig[Inspector].prio = 2; + break; + case 'N': + defconfig[Inspector].val.i = 1; + defconfig[Inspector].prio = 2; + break; + case 'r': + scriptfile = EARGF(usage()); + break; + case 's': + defconfig[JavaScript].val.i = 0; + defconfig[JavaScript].prio = 2; + break; + case 'S': + defconfig[JavaScript].val.i = 1; + defconfig[JavaScript].prio = 2; + break; + case 't': + defconfig[StrictTLS].val.i = 0; + defconfig[StrictTLS].prio = 2; + break; + case 'T': + defconfig[StrictTLS].val.i = 1; + defconfig[StrictTLS].prio = 2; + break; + case 'u': + fulluseragent = EARGF(usage()); + break; + case 'v': + die("surf-"VERSION", see LICENSE for © details\n"); + case 'w': + showxid = 1; + break; + case 'x': + defconfig[Certificate].val.i = 0; + defconfig[Certificate].prio = 2; + break; + case 'X': + defconfig[Certificate].val.i = 1; + defconfig[Certificate].prio = 2; + break; + case 'z': + defconfig[ZoomLevel].val.f = strtof(EARGF(usage()), NULL); + defconfig[ZoomLevel].prio = 2; + break; + default: + usage(); + } ARGEND; + if (argc > 0) + arg.v = argv[0]; + else + arg.v = "about:blank"; + + setup(); + c = newclient(NULL); + showview(NULL, c); + + loaduri(c, &arg); + updatetitle(c); + + gtk_main(); + cleanup(); + + return 0; +} diff --git a/stuff/manual-programs/suckless/surf/surf.o b/stuff/manual-programs/suckless/surf/surf.o new file mode 100644 index 0000000000000000000000000000000000000000..addfe306d240dd4325cbe8ba8d0be8b97eb7bb9c GIT binary patch literal 72976 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 literal 0 HcmV?d00001 diff --git a/stuff/manual-programs/suckless/surf/surf.png b/stuff/manual-programs/suckless/surf/surf.png new file mode 100644 index 0000000000000000000000000000000000000000..f5b2ab149a2ed429e8875541b80a7cf974ded0c4 GIT binary patch literal 240 zcmeAS@N?(olHy`uVBq!ia0vp^;Xtgx$P6Sm7Jab>QjEnx?oJHr&dIz4a@YcVLR^6~ z5G+mKc^*hHmIV0)GdMiEkp|)!MP|ku_QG`p**uBL&4qCHz2%`PaLR-y~NYkmHj3smw=`0t2gS7Kp{g< z7sn8Z%UjQGfr(=)l +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "common.h" + +#define LENGTH(x) (sizeof(x) / sizeof(x[0])) + +static WebKitWebExtension *webext; +static int sock; + +/* + * Return: + * 0 No data processed: need more data + * > 0 Amount of data processed or discarded + */ +static size_t +evalmsg(char *msg, size_t sz) +{ + char js[48]; + WebKitWebPage *page; + JSCContext *jsc; + JSCValue *jsv; + + if (!(page = webkit_web_extension_get_page(webext, msg[0]))) + return sz; + + if (sz < 2) + return 0; + + jsc = webkit_frame_get_js_context(webkit_web_page_get_main_frame(page)); + jsv = NULL; + + switch (msg[1]) { + case 'h': + if (sz < 3) { + sz = 0; + break; + } + sz = 3; + snprintf(js, sizeof(js), + "window.scrollBy(window.innerWidth/100*%hhd,0);", + msg[2]); + jsv = jsc_context_evaluate(jsc, js, -1); + break; + case 'v': + if (sz < 3) { + sz = 0; + break; + } + sz = 3; + snprintf(js, sizeof(js), + "window.scrollBy(0,window.innerHeight/100*%hhd);", + msg[2]); + jsv = jsc_context_evaluate(jsc, js, -1); + break; + default: + fprintf(stderr, "%s:%d:evalmsg: unknown cmd(%zu): '%#x'\n", + __FILE__, __LINE__, sz, msg[1]); + } + + g_object_unref(jsc); + if (jsv) + g_object_unref(jsv); + + return sz; +} + +static gboolean +readsock(GIOChannel *s, GIOCondition c, gpointer unused) +{ + static char msg[MSGBUFSZ]; + static size_t msgoff; + GError *gerr = NULL; + size_t sz; + gsize rsz; + + if (g_io_channel_read_chars(s, msg+msgoff, sizeof(msg)-msgoff, &rsz, &gerr) != + G_IO_STATUS_NORMAL) { + if (gerr) { + fprintf(stderr, "webext: error reading socket: %s\n", + gerr->message); + g_error_free(gerr); + } + return TRUE; + } + if (msgoff >= sizeof(msg)) { + fprintf(stderr, "%s:%d:%s: msgoff: %zu", __FILE__, __LINE__, __func__, msgoff); + return FALSE; + } + + for (rsz += msgoff; rsz; rsz -= sz) { + sz = evalmsg(msg, rsz); + if (sz == 0) { + /* need more data */ + break; + } + if (sz != rsz) { + /* continue processing message */ + memmove(msg, msg+sz, rsz-sz); + } + } + msgoff = rsz; + + return TRUE; +} + +static void +pageusermessagereply(GObject *o, GAsyncResult *r, gpointer page) +{ + WebKitUserMessage *m; + GUnixFDList *gfd; + GIOChannel *gchansock; + const char *name; + int nfd; + + m = webkit_web_page_send_message_to_view_finish(page, r, NULL); + name = webkit_user_message_get_name(m); + if (strcmp(name, "surf-pipe") != 0) { + fprintf(stderr, "webext-surf: Unknown User Reply: %s\n", name); + return; + } + + gfd = webkit_user_message_get_fd_list(m); + if ((nfd = g_unix_fd_list_get_length(gfd)) != 1) { + fprintf(stderr, "webext-surf: Too many file-descriptors: %d\n", nfd); + return; + } + + sock = g_unix_fd_list_get(gfd, 0, NULL); + + gchansock = g_io_channel_unix_new(sock); + g_io_channel_set_encoding(gchansock, NULL, NULL); + g_io_channel_set_flags(gchansock, g_io_channel_get_flags(gchansock) + | G_IO_FLAG_NONBLOCK, NULL); + g_io_channel_set_close_on_unref(gchansock, TRUE); + g_io_add_watch(gchansock, G_IO_IN, readsock, NULL); +} + +void +pagecreated(WebKitWebExtension *e, WebKitWebPage *p, gpointer unused) +{ + WebKitUserMessage *msg; + + msg = webkit_user_message_new("page-created", NULL); + webkit_web_page_send_message_to_view(p, msg, NULL, pageusermessagereply, p); +} + +G_MODULE_EXPORT void +webkit_web_extension_initialize(WebKitWebExtension *e) +{ + webext = e; + + g_signal_connect(G_OBJECT(e), "page-created", + G_CALLBACK(pagecreated), NULL); +} diff --git a/stuff/manual-programs/suckless/surf/webext-surf.o b/stuff/manual-programs/suckless/surf/webext-surf.o new file mode 100644 index 0000000000000000000000000000000000000000..b691525d68c9c071ab70a3aafd6303c9a9cfaba2 GIT binary patch literal 6560 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 ato3#J=MQJNPlels5sc)^UQxgL?f(N|{WyyN literal 0 HcmV?d00001 diff --git a/stuff/manual-programs/suckless/surf/webext-surf.so b/stuff/manual-programs/suckless/surf/webext-surf.so new file mode 100644 index 0000000000000000000000000000000000000000..8a38856443785a22df3a416e2d031aefedf9cabd GIT binary patch literal 16728 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 `|!i9 z1=-WShG?i(#`(Ueq$G4s6zI%Pa;bDB2eK4eOSxAz~CN*>}g*@v{x!q|4EPN zAjomgLp<$!hz6y-v;PuiBTzx#WN+@XVL!Q6 zC=>mK#TKj1_AxaSpHaxugwb;c`fk{%Pdw3=z!vvxWKYi}X4V4;h4chB&lCO{2ypI@ zJ?(esJMcLf7@YrD$c~QV8-QW_$ez9nI(0K@GZqxY{7?2oe+&|$c9Nzp!5AF{vuRRhx$+Zx>;%OCq+q}{(c2G_TM>9vUi?;sEfr)Y3>P$ z__FY(t|C1epo~40FA+<}oc$zv?xM=Tfl?|Ns{{`1f B!Vv%f literal 0 HcmV?d00001 diff --git a/stuff/scripts/system/backup/backup.sh b/stuff/scripts/system/backup/backup.sh new file mode 100755 index 0000000..16559d1 --- /dev/null +++ b/stuff/scripts/system/backup/backup.sh @@ -0,0 +1,30 @@ +cd ~/ + +fsynca () { + # t? + rsync -RUurvn --size-only --delete-after $exclude $syncfile "$target" +} + +fsyncb () { + printf "===confirm changes?\n" + read -p "y/n: " uinput + if [ "$uinput" != "n" ] && [ "$uinput" != "N" ]; then + printf "\n\n\n" + rsync -PRUurv --size-only --delete-after $exclude $syncfile "$target" + printf "\n===end sync\n---------\n\n" + fi +} + +syncfile="stuff .bash_profile .bashrc .surf .wezterm.lua .tmux.conf .gtkrc-2.0 .profile .urlview .vimrc .xinitrc .Xresources .zshrc .newsboat .gnupg .ssh .local/bin/lf-gadgets .config/dwm .config/awesome .config/gtk-3.0 .config/rofi .config/lf .config/picom.conf .config/nvim .config/screenkey.json .config/vesktop/themes .keepass .config/Pinta" + +#sync game stuff +target="/home/iceyrazor/mnt-backups/LINUX FILES/home/iceyrazor" +exclude="--exclude **/cc-survival --exclude node_modules --exclude dontsync --exclude **/iceys-linux-stuffs" + + +fsynca + +printf "==CC-survival unsynced\n\n" + +fsyncb + diff --git a/stuff/scripts/system/backup/copy-to-git.sh b/stuff/scripts/system/backup/copy-to-git.sh new file mode 100755 index 0000000..ad2a42d --- /dev/null +++ b/stuff/scripts/system/backup/copy-to-git.sh @@ -0,0 +1,21 @@ +cd ~/ + +fsync () { + rsync -RUurvn --size-only --delete-after $exclude $syncfile "$target" + printf "===commit these changes?\n" + read -p "y/n: " uinput + if [ "$uinput" != "n" ] && [ "$uinput" != "N" ]; then + printf "\n\n\n" + rsync -PRUurv --size-only --delete-after $exclude $syncfile "$target" + printf "\n===end sync\n---------\n\n" + fi +} + +syncfile=".bash_profile .bashrc .gtkrc-2.0 .wezterm.lua .profile .urlview .vimrc .Xresources .zshrc .config/dwm .config/awesome .config/rofi .config/lf .config/picom.conf .config/nvim .config/screenkey.json stuff/manual-programs/suckless" + +syncfile="$syncfile stuff/scripts/system/stbar stuff/scripts/system/url-handler.sh stuff/scripts/system/backup/copy-to-git.sh stuff/scripts/system/backup/backup.sh" +syncfile="$syncfile stuff/scripts/system/neoboot.sh stuff/scripts/system/math.sh stuff/scripts/system/bri.sh stuff/scripts/system/restart-pipe.sh stuff/scripts/system/set-pri-java.sh" +target=~/stuff/iceys-linux-stuffs +exclude="--exclude check_weth.sh --exclude lua-ls-cc-tweaked --exclude .config/nvim/plugin" + +fsync diff --git a/stuff/scripts/system/bri.sh b/stuff/scripts/system/bri.sh new file mode 100755 index 0000000..b943f30 --- /dev/null +++ b/stuff/scripts/system/bri.sh @@ -0,0 +1 @@ +echo "$1" > /sys/class/backlight/intel_backlight/brightness diff --git a/stuff/scripts/system/math.sh b/stuff/scripts/system/math.sh new file mode 100755 index 0000000..26d4854 --- /dev/null +++ b/stuff/scripts/system/math.sh @@ -0,0 +1,13 @@ +#!/bin/bash +expression=$1 +precision=$2 + +if [ "$precision" == "" ]; then + precision=1; +fi; + +# Perform arithmetic operation using awk +result=$(awk "BEGIN {printf \"%.${precision}f\n\", $expression}" | sed 's/\.0$//') + +# Print the result +echo "$result" diff --git a/stuff/scripts/system/neoboot.sh b/stuff/scripts/system/neoboot.sh new file mode 100755 index 0000000..2df07de --- /dev/null +++ b/stuff/scripts/system/neoboot.sh @@ -0,0 +1,28 @@ +normal() { + randnum=$(($RANDOM % 2)) + + if [ "$randnum" == "1" ]; then + # fastfetch --localip-show-ipv4 0 # | lolcat -as 10000 -S 100 + fortune | cowsay -f fox | lolcat + else + fortune | cowsay -f dragon | lolcat + fi + printf "\n--------------------------------------------------------\n" | lolcat + lsblk --filter 'NAME=~"sd[abcde]"' -o NAME,MOUNTPOINTS | lolcat +} + +laptop() { + if [ "$(($RANDOM % 2))" == "1" ]; then + fastfetch --localip-show-ipv4 0 | lolcat -as 10000 -S 100 + else + uwufetch | lolcat -as 10000 -S 100 + fi + printf "\n--------------------------------------------------------\n" | lolcat -S 100 + lsblk --filter 'NAME=~"sd[abcde]"' -o NAME,MOUNTPOINTS | lolcat -as 10000 -S 100 +} + +if [[ "$(cat /etc/hostname)" == "iceynethp1" ]]; then + laptop +else + normal +fi diff --git a/stuff/scripts/system/restart-pipe.sh b/stuff/scripts/system/restart-pipe.sh new file mode 100755 index 0000000..ec693dc --- /dev/null +++ b/stuff/scripts/system/restart-pipe.sh @@ -0,0 +1 @@ +systemctl --user restart wireplumber pipewire pipewire-pulse diff --git a/stuff/scripts/system/set-pri-java.sh b/stuff/scripts/system/set-pri-java.sh new file mode 100755 index 0000000..35a9769 --- /dev/null +++ b/stuff/scripts/system/set-pri-java.sh @@ -0,0 +1 @@ +sudo renice -20 -p $(sudo pidof java) diff --git a/stuff/scripts/system/stbar/config.txt b/stuff/scripts/system/stbar/config.txt new file mode 100644 index 0000000..3137407 --- /dev/null +++ b/stuff/scripts/system/stbar/config.txt @@ -0,0 +1,2 @@ +full_stat:false +wifi_device:wlo1 diff --git a/stuff/scripts/system/stbar/killbar.sh b/stuff/scripts/system/stbar/killbar.sh new file mode 100755 index 0000000..7e76af2 --- /dev/null +++ b/stuff/scripts/system/stbar/killbar.sh @@ -0,0 +1,10 @@ +pids=$(ps -AO pid | awk '/stbar.sh|newsboat-fetch.sh/ {print $1}') +# pids=$(pstree -pla | grep stbar | sed 's,|,,g' | sed 's/ //g' | sed 's/^ //g' | sed 's/ .*//' | sed 's/[^0-9]*//g') +# pids2=$(ps -AO pid | grep "sh ./newsboat-fetch.sh" | sed 's/S.*//g' | sed 's/^ *//g') + + +echo $pids +$(sleep 3 && xsetroot -name "") & disown + +sudo kill -KILL $pids +doas kill -KILL $pids diff --git a/stuff/scripts/system/stbar/stbar-awesome.sh b/stuff/scripts/system/stbar/stbar-awesome.sh new file mode 100755 index 0000000..84c1894 --- /dev/null +++ b/stuff/scripts/system/stbar/stbar-awesome.sh @@ -0,0 +1,81 @@ +#!/bin/bash +delim='|' + +curr_dir="$(cd "$(dirname "$0")" && pwd)" +#wifi_device=$(cat $curr_dir/config.txt | grep wifi_device | sed 's/wifi_device://') +wifi_device="wlp4s0" +# curr_dir/check_weth.sh "$cur_dir" & + + + +status(){ + +echo " " + +#wifi up or no +sed "s/down/\:\(/;s/up/\:\)/" /sys/class/net/$wifi_device/operstate + +echo "$delim" + +if [ "$(ls /sys/class/power_supply/BAT0/)" ]; then + bat_power=$(cat /sys/class/power_supply/BAT0/capacity) + + echo $bat_is_flash + if (( $bat_power < 15 )); then + bat_power=$bat_power%!!!!!!!!!!! + else + bat_power=$bat_power% + fi + + echo $bat_power + + echo "$delim" +fi + +#rss + +echo RSS:$(newsboat -x print-unread|sed "s/\s.*//; s/Error:/IA/") + +echo "$delim" + +if [ "$(cat $curr_dir/config.txt | grep full_stat)" == "full_stat:true" ]; then + #cpu + echo CPU:$(ps axch -o cmd:15,%cpu --sort=-%cpu | sed "1q")% + + echo "$delim" + + #mem + echo Mem:$(free -mlw | grep Mem: | sed "s/Mem\:\W*[0-9]*\W*//; s/ .*//") + echo $(ps axch -o cmd:15,%mem --sort=-%mem | sed "1q")% + +else + #cpu + echo CPU:$(ps axch -o cmd:15,%cpu --sort=-%cpu | sed "1q" | sed 's/.* //')% + + #mem + echo Mem:$(free -mlw | grep Mem: | sed "s/Mem\:\W*[0-9]*\W*//; s/ .*//") + +fi +echo "$delim" + +#space +#echo \/$(df -h | grep /dev/nvme0n1p3 | sed "s/\/dev\/nvme0n1p3 *[0-9]*.[0-9]*. *[0-9]*.[0-9]*. *//" | sed "s/ .*//") + +#echo \~$(df -h | grep /dev/nvme0n1p4 | sed "s/\/dev\/nvme0n1p4 *[0-9]*.[0-9]*. *[0-9]*.[0-9]*. *//" | sed "s/ .*//") +echo $(df -h -x=used /dev/mapper/system-root | sed '1d' | awk '{print $4}') + +echo "$delim" + +#weather + +if [ "$(cat $curr_dir/weth_str.txt)" != "" ]; then + printf "$(cat $curr_dir/weth_str.txt)" + echo "$delim" +fi + +} + +#while :; do + echo "$(status | tr '\n' ' '0)" +# sleep 1s +#end diff --git a/stuff/scripts/system/stbar/stbar.sh b/stuff/scripts/system/stbar/stbar.sh new file mode 100755 index 0000000..6ca704d --- /dev/null +++ b/stuff/scripts/system/stbar/stbar.sh @@ -0,0 +1,84 @@ +#!/bin/bash +delim='|' + +curr_dir="$(cd "$(dirname "$0")" && pwd)" +wifi_device=$(cat $curr_dir/config.txt | grep wifi_device | sed 's/wifi_device://') +# curr_dir/check_weth.sh "$cur_dir" & + + + +status(){ + +echo " " + +#wifi up or no +sed "s/down/\:\(/;s/up/\:\)/" /sys/class/net/$wifi_device/operstate + +echo "$delim" + +#bat +bat_power=$(cat /sys/class/power_supply/BAT0/capacity) + +echo $bat_is_flash +if (( $bat_power < 15 )); then + bat_power=$bat_power%!!!!!!!!!!! +else + bat_power=$bat_power% +fi + +echo $bat_power + +echo "$delim" + +#rss + +echo RSS:$(newsboat -x print-unread|sed "s/\s.*//; s/Error:/IA/") + +echo "$delim" + +if [ "$(cat $curr_dir/config.txt | grep full_stat)" == "full_stat:true" ]; then + #cpu + echo CPU:$(ps axch -o cmd:15,%cpu --sort=-%cpu | sed "1q")% + + echo "$delim" + + #mem + echo Mem:$(free -mlw | grep Mem: | sed "s/Mem\:\W*[0-9]*\W*//; s/ .*//") + echo $(ps axch -o cmd:15,%mem --sort=-%mem | sed "1q")% + +else + #cpu + echo CPU:$(ps axch -o cmd:15,%cpu --sort=-%cpu | sed "1q" | sed 's/.* //')% + + #mem + echo Mem:$(free -mlw | grep Mem: | sed "s/Mem\:\W*[0-9]*\W*//; s/ .*//") + +fi +echo "$delim" + +#space +echo \/$(df -h | grep /dev/nvme0n1p3 | sed "s/\/dev\/nvme0n1p3 *[0-9]*.[0-9]*. *[0-9]*.[0-9]*. *//" | sed "s/ .*//") + +echo \~$(df -h | grep /dev/nvme0n1p4 | sed "s/\/dev\/nvme0n1p4 *[0-9]*.[0-9]*. *[0-9]*.[0-9]*. *//" | sed "s/ .*//") + +echo "$delim" + +#weather + +if [ "$(cat $curr_dir/weth_str.txt)" != "" ]; then + printf "$(cat $curr_dir/weth_str.txt)" + echo "$delim" +fi + + +#date +date '+%a %m/%d/%Y %I:%M%p' + +} + + +while :; do + xsetroot -name "$(status | tr '\n' ' '0)" + sleep 1s +done + diff --git a/stuff/scripts/system/stbar/weth_str.txt b/stuff/scripts/system/stbar/weth_str.txt new file mode 100755 index 0000000..e69de29 diff --git a/stuff/scripts/system/url-handler.sh b/stuff/scripts/system/url-handler.sh new file mode 100755 index 0000000..b5a1a3a --- /dev/null +++ b/stuff/scripts/system/url-handler.sh @@ -0,0 +1,18 @@ + +url=$@ +prompt_message="Open with:" + +echo $url + +choices=" +clipboard +firefox +" + +choice=$(echo "$choices" | sed /^$/d | dmenu -i -p "$prompt_message") + +if [ "$choice" == "clipboard" ]; then + printf "$url" | xclip -selection clipboard +else + $choice "$url" +fi