sites

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit 38fdd48a0d254359e594a99ecc6990f801b065c4
parent 0ee04abe764f0293cae1390edd4dabec6898af55
Author: Philippe Gras <philippe.gras@free.fr>
Date:   Sun,  6 Mar 2016 00:11:41 +0100

Merge remote-tracking branch 'origin/master'

Diffstat:
Mdwm.suckless.org/dwmgetstatus.md | 4++--
Mdwm.suckless.org/dwmgetstatus.sh | 2+-
Adwm.suckless.org/dwmstatus/dwmclock-netstat.c | 140+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdwm.suckless.org/dwmstatus/index.md | 3++-
Mdwm.suckless.org/dwmstatus/profil-dwmstatus-1.0.c | 10+++++-----
Ddwm.suckless.org/dwmstatus/suspend-statusbar.c | 219-------------------------------------------------------------------------------
Mdwm.suckless.org/index.md | 2+-
Mdwm.suckless.org/patches/ansistatuscolors.md | 8++++----
Mdwm.suckless.org/patches/attachabove.md | 6+++---
Mdwm.suckless.org/patches/attachaside.md | 6+++---
Mdwm.suckless.org/patches/better-borders.md | 5++++-
Mdwm.suckless.org/patches/center.md | 3++-
Adwm.suckless.org/patches/centeredmaster.c | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdwm.suckless.org/patches/centeredmaster.md | 66++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mdwm.suckless.org/patches/combo.md | 6++++--
Mdwm.suckless.org/patches/dualstatus.md | 2+-
Ddwm.suckless.org/patches/dwm-10e232f9ace7-push.diff | 65-----------------------------------------------------------------
Ddwm.suckless.org/patches/dwm-14343e69cc59-systray.diff | 687-------------------------------------------------------------------------------
Adwm.suckless.org/patches/dwm-20151110-5ed9c48-keycode.patch | 146+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/dwm-3465bed290ab-maximize_vert_horz.diff | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ddwm.suckless.org/patches/dwm-35db6d8-fancybar.diff | 69---------------------------------------------------------------------
Ddwm.suckless.org/patches/dwm-6.0-xft.diff | 229-------------------------------------------------------------------------------
Mdwm.suckless.org/patches/dwm-6.1-attachabove.diff | 29++++++++++++++---------------
Mdwm.suckless.org/patches/dwm-6.1-better-borders.diff | 141+++++++++++++++++++++++++++++++++++++++----------------------------------------
Adwm.suckless.org/patches/dwm-6.1-center.diff | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdwm.suckless.org/patches/dwm-6.1-centeredmaster.diff | 49+++++++++++++++++++++++++------------------------
Adwm.suckless.org/patches/dwm-6.1-combo.diff | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdwm.suckless.org/patches/dwm-6.1-dualstatus.diff | 69+++++++++++++++++++++++++++++++++++----------------------------------
Adwm.suckless.org/patches/dwm-6.1-fancybar.diff | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdwm.suckless.org/patches/dwm-6.1-fancybarclickable.diff | 221+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mdwm.suckless.org/patches/dwm-6.1-hide_vacant_tags.diff | 18+++++++++---------
Adwm.suckless.org/patches/dwm-6.1-horizgrid.diff | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ddwm.suckless.org/patches/dwm-6.1-make-the-borders-of-urgent-windows-a-different-color.diff | 61-------------------------------------------------------------
Adwm.suckless.org/patches/dwm-6.1-mark.diff | 231+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/dwm-6.1-pertag-tab-v2b.diff | 841+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdwm.suckless.org/patches/dwm-6.1-pertag.diff | 101+++++++++++++++++++++++++++++++++++++------------------------------------------
Adwm.suckless.org/patches/dwm-6.1-pertag_without_bar.diff | 161+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/dwm-6.1-push_no_master.diff | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/dwm-6.1-resizecorners.diff | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdwm.suckless.org/patches/dwm-6.1-single_window_no_border.diff | 61+++++++++++++++++++++++++++++--------------------------------
Mdwm.suckless.org/patches/dwm-6.1-statuscolors.diff | 206+++++++++++++++++++++++++++++++++++++------------------------------------------
Adwm.suckless.org/patches/dwm-6.1-swallowing.diff | 377+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdwm.suckless.org/patches/dwm-6.1-systray.diff | 344+++++++++++++++++++++++++++++++++++++++----------------------------------------
Adwm.suckless.org/patches/dwm-6.1-tab-v2b.diff | 511+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/dwm-6.1-urg-border.diff | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdwm.suckless.org/patches/dwm-6.1-uselessgap.diff | 68+++++++++++++++++++++++++++++++-------------------------------------
Adwm.suckless.org/patches/dwm-6.1-warp.diff | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rdwm.suckless.org/patches/dwm-10e232f9ace7-attachabove.diff -> dwm.suckless.org/patches/dwm-git-20120406-attachabove.diff | 0
Rdwm.suckless.org/patches/dwm-10e232f9ace7-pertag.diff -> dwm.suckless.org/patches/dwm-git-20120406-pertag.diff | 0
Rdwm.suckless.org/patches/dwm-c794a9f5ae5e-systray.diff -> dwm.suckless.org/patches/dwm-git-20130119-systray.diff | 0
Adwm.suckless.org/patches/dwm-git-20160103-systray.diff | 689+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/dwm-master_2015-12-19_3465be-pertag-tab-v2b.diff | 844+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/dwm-master_2015-12-19_3465be-tab-v2b.diff | 500+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdwm.suckless.org/patches/exresize.md | 2+-
Ddwm.suckless.org/patches/fancybar-c794a9f5ae5e.patch | 124-------------------------------------------------------------------------------
Ddwm.suckless.org/patches/fancybar-r1496.diff | 126-------------------------------------------------------------------------------
Mdwm.suckless.org/patches/fancybar.md | 11+++--------
Mdwm.suckless.org/patches/fancybarclickable.md | 11+++++++----
Mdwm.suckless.org/patches/fibonacci.md | 8+-------
Mdwm.suckless.org/patches/flextile.md | 2+-
Mdwm.suckless.org/patches/focusonclick.md | 4++--
Mdwm.suckless.org/patches/hide_vacant_tags.md | 3++-
Rdwm.suckless.org/patches/dwm-5.6.1-attachabove.diff -> dwm.suckless.org/patches/historical/dwm-5.6.1-attachabove.diff | 0
Rdwm.suckless.org/patches/dwm-5.6.1-attachaside.diff -> dwm.suckless.org/patches/historical/dwm-5.6.1-attachaside.diff | 0
Rdwm.suckless.org/patches/dwm-5.7.2-attachaside.diff -> dwm.suckless.org/patches/historical/dwm-5.7.2-attachaside.diff | 0
Rdwm.suckless.org/patches/dwm-5.8.2-focusonclick.diff -> dwm.suckless.org/patches/historical/dwm-5.8.2-focusonclick.diff | 0
Rdwm.suckless.org/patches/dwm-5.8.2-pertag.diff -> dwm.suckless.org/patches/historical/dwm-5.8.2-pertag.diff | 0
Rdwm.suckless.org/patches/dwm-5.8.2-pertag_without_bar.diff -> dwm.suckless.org/patches/historical/dwm-5.8.2-pertag_without_bar.diff | 0
Adwm.suckless.org/patches/historical/dwm-6.0-xft.diff | 259+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rdwm.suckless.org/patches/dwm-6.1-xft-with-fallback-font.diff -> dwm.suckless.org/patches/historical/dwm-6.1-xft-with-fallback-font.diff | 0
Rdwm.suckless.org/patches/dwm-cdec978-center.diff -> dwm.suckless.org/patches/historical/dwm-cdec978-center.diff | 0
Rdwm.suckless.org/patches/dwm-r1508-focusonclick.diff -> dwm.suckless.org/patches/historical/dwm-git-20100321-focusonclick.diff | 0
Adwm.suckless.org/patches/historical/dwm-master_2015-10-20_7e1182c-pertag-tab-v2b.diff | 692+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/historical/dwm-master_2015-10-20_7e1182c-tab-v2b.diff | 506+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ddwm.suckless.org/patches/historical/dwm-r1525-warp.diff | 99-------------------------------------------------------------------------------
Rdwm.suckless.org/patches/dwm-r1578-pertag.diff -> dwm.suckless.org/patches/historical/dwm-r1578-pertag.diff | 0
Ddwm.suckless.org/patches/historical/push-5.3.c | 56--------------------------------------------------------
Ddwm.suckless.org/patches/historical/push-5.6.c | 58----------------------------------------------------------
Adwm.suckless.org/patches/historical/xft.md | 44++++++++++++++++++++++++++++++++++++++++++++
Adwm.suckless.org/patches/horizgrid.md | 37+++++++++++++++++++++++++++++++++++++
Mdwm.suckless.org/patches/index.md | 15+++++++++++++--
Mdwm.suckless.org/patches/keycode.md | 6++++--
Adwm.suckless.org/patches/mark.md | 38++++++++++++++++++++++++++++++++++++++
Mdwm.suckless.org/patches/movestack.md | 2+-
Mdwm.suckless.org/patches/noborder.md | 2+-
Mdwm.suckless.org/patches/pertag.md | 18+++++++++++-------
Ddwm.suckless.org/patches/push.c | 58----------------------------------------------------------
Mdwm.suckless.org/patches/push.md | 13+++++--------
Mdwm.suckless.org/patches/resizecorners.md | 2++
Mdwm.suckless.org/patches/statuscolors.md | 2+-
Adwm.suckless.org/patches/swallow.md | 34++++++++++++++++++++++++++++++++++
Mdwm.suckless.org/patches/systray.md | 7++++---
Mdwm.suckless.org/patches/tab.md | 1+
Mdwm.suckless.org/patches/urgentborder.md | 4++--
Mdwm.suckless.org/patches/warp.md | 13+++++++------
Ddwm.suckless.org/patches/xft-with-fallback-fonts.md | 36------------------------------------
Ddwm.suckless.org/patches/xft.md | 19-------------------
Mdwm.suckless.org/scripts/simple_monitors.md | 10++++++++--
Mdwm.suckless.org/tutorial.md | 53+++++++++++++++++++++++++++++++++++------------------
Mst.suckless.org/index.md | 2+-
Dst.suckless.org/patches/1clipboard.diff | 14--------------
Dst.suckless.org/patches/1clipboard.md | 25-------------------------
Mst.suckless.org/patches/argbbg.md | 13+++++++------
Mst.suckless.org/patches/boldcolor.md | 16+++++++---------
Ast.suckless.org/patches/clipboard.md | 21+++++++++++++++++++++
Dst.suckless.org/patches/configwordbreak.md | 29-----------------------------
Mst.suckless.org/patches/copyurl.md | 21++++++++++++++-------
Mst.suckless.org/patches/delkey.md | 10++++++----
Mst.suckless.org/patches/externalpipe.md | 40++++++++++++++++------------------------
Dst.suckless.org/patches/hide_X_cursor.md | 20--------------------
Ast.suckless.org/patches/hidecursor.md | 21+++++++++++++++++++++
Ast.suckless.org/patches/openbsd.md | 37+++++++++++++++++++++++++++++++++++++
Mst.suckless.org/patches/scrollback.md | 40++++++++++++++++++++++++++++------------
Ast.suckless.org/patches/solarized.md | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dst.suckless.org/patches/solarized_color_scheme.md | 58----------------------------------------------------------
Ast.suckless.org/patches/spoiler.md | 28++++++++++++++++++++++++++++
Rst.suckless.org/patches/st-0.3-configwordbreak.diff -> st.suckless.org/patches/st-0.3-wordbreak.diff | 0
Rst.suckless.org/patches/st-0.4-configwordbreak.diff -> st.suckless.org/patches/st-0.4-wordbreak.diff | 0
Mst.suckless.org/patches/st-0.4.1-externalpipe.diff | 28++++++++--------------------
Rst.suckless.org/patches/st-0.4.1-configwordbreak.diff -> st.suckless.org/patches/st-0.4.1-wordbreak.diff | 0
Ast.suckless.org/patches/st-0.5-externalpipe.diff | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-0.5-hidecursor.diff | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dst.suckless.org/patches/st-0.5-hidexcursor.diff | 96-------------------------------------------------------------------------------
Mst.suckless.org/patches/st-0.5-no-bold-colors.diff | 3++-
Ast.suckless.org/patches/st-0.5-solarized-dark.diff | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-0.5-solarized-light.diff | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rst.suckless.org/patches/st-0.5-configwordbreak.diff -> st.suckless.org/patches/st-0.5-wordbreak.diff | 0
Ast.suckless.org/patches/st-0.6-argbbg.diff | 170+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-0.6-clipboard.diff | 13+++++++++++++
Ast.suckless.org/patches/st-0.6-copyurl.diff | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-0.6-delkey.diff | 45+++++++++++++++++++++++++++++++++++++++++++++
Mst.suckless.org/patches/st-0.6-externalpipe.diff | 14+-------------
Ast.suckless.org/patches/st-0.6-hidecursor.diff | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dst.suckless.org/patches/st-0.6-hidexcursor.diff | 100-------------------------------------------------------------------------------
Ast.suckless.org/patches/st-0.6-solarized-dark.diff | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-0.6-solarized-light.diff | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-0.6-spoiler.diff | 22++++++++++++++++++++++
Dst.suckless.org/patches/st-git-20141017-copyurl.diff | 84-------------------------------------------------------------------------------
Dst.suckless.org/patches/st-git-20141122-argbbg.diff | 169-------------------------------------------------------------------------------
Dst.suckless.org/patches/st-git-20150601-argbbg.diff | 169-------------------------------------------------------------------------------
Dst.suckless.org/patches/st-git-20150601-copyurl.diff | 85-------------------------------------------------------------------------------
Dst.suckless.org/patches/st-git-20150611-argbbg.diff | 170-------------------------------------------------------------------------------
Dst.suckless.org/patches/st-git-20150824-externalpipe.diff | 75---------------------------------------------------------------------------
Ast.suckless.org/patches/st-git-20150917-clipboard.diff | 13+++++++++++++
Ast.suckless.org/patches/st-git-20150917-delkey.diff | 45+++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-git-20150917-hidecursor.diff | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-git-20150917-no-bold-colors.diff | 13+++++++++++++
Ast.suckless.org/patches/st-git-20150917-solarized-dark.diff | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-git-20150917-solarized-light.diff | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-git-20150920-openbsd.diff | 27+++++++++++++++++++++++++++
Ast.suckless.org/patches/st-git-20150922-spoiler.diff | 22++++++++++++++++++++++
Ast.suckless.org/patches/st-git-20151106-scrollback-mouse.diff | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-git-20151119-solarized-dark.diff | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-git-20151119-solarized-light.diff | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-git-20151217-scrollback.diff | 388+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-git-20160131-argbbg.diff | 161+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-git-20160203-scrollback-mouse-altscreen.diff | 40++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-git-20160204-externalpipe.diff | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-git-20160209-visualbell.diff | 42++++++++++++++++++++++++++++++++++++++++++
Ast.suckless.org/patches/st-git-20160210-copyurl.diff | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dst.suckless.org/patches/st-git-delkey.diff | 45---------------------------------------------
Dst.suckless.org/patches/st-git-hidexcursor.diff | 104-------------------------------------------------------------------------------
Dst.suckless.org/patches/st-no-bold-colors.diff | 13-------------
Dst.suckless.org/patches/st-on-openbsd.diff | 25-------------------------
Dst.suckless.org/patches/st-scrollback-shift-mouse.diff | 408-------------------------------------------------------------------------------
Dst.suckless.org/patches/st-scrollback.diff | 343-------------------------------------------------------------------------------
Dst.suckless.org/patches/st-solarized-dark.diff | 64----------------------------------------------------------------
Dst.suckless.org/patches/st-solarized-light.diff | 64----------------------------------------------------------------
Dst.suckless.org/patches/st_on_openbsd.md | 42------------------------------------------
Ast.suckless.org/patches/visualbell.md | 24++++++++++++++++++++++++
Ast.suckless.org/patches/wordbreak.md | 29+++++++++++++++++++++++++++++
Dst.suckless.org/patches/xterm_fallback.diff | 51---------------------------------------------------
Dst.suckless.org/patches/xterm_fallback.md | 22----------------------
Mst.suckless.org/screenshots/index.md | 7+++----
Asta.li/README | 1+
Dsta.li/_werc/config | 3---
Dsta.li/faq.md | 146-------------------------------------------------------------------------------
Dsta.li/filesystem.md | 29-----------------------------
Dsta.li/index.md | 36------------------------------------
Dsta.li/masterplan.md | 58----------------------------------------------------------
Dsta.li/sandbox.md | 42------------------------------------------
Dsta.li/stali.png | 0
Dsta.li/technologies.md | 34----------------------------------
Asuckless.org/coding_style.md | 161+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msuckless.org/community.md | 32++++++++++++++++++++++++++++----
Msuckless.org/conference/2013.md | 85+++++++++++++++++++++++++++++++++----------------------------------------------
Asuckless.org/conference/2015.md | 165+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asuckless.org/conference/genua.png | 0
Msuckless.org/conference/index.md | 27++++++---------------------
Asuckless.org/conference/slcon2015-s.png | 0
Asuckless.org/conference/slcon2015.png | 0
Msuckless.org/donations.md | 2+-
Msuckless.org/index.md | 71++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Asuckless.org/jan_on_sj.pdf | 0
Msuckless.org/other_projects.md | 20++++++++++----------
Msuckless.org/people/20h.md | 20+++++++++++++++++---
Asuckless.org/people/hiltjo.md | 12++++++++++++
Msuckless.org/people/k0ga.md | 1+
Asuckless.org/people/maandree.md | 9+++++++++
Msuckless.org/philosophy.md | 4++++
Msuckless.org/project_ideas.md | 78+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Msuckless.org/rocks.md | 19+++++++++++++------
Dsuckless.org/style.md | 161-------------------------------------------------------------------------------
Msuckless.org/sucks/index.md | 36++++++++++++++++++++++++++++++++++++
Msuckless.org/sucks/systemd.md | 5+++++
Asuckless.org/sucks/web.md | 26++++++++++++++++++++++++++
Msuckless.org/wiki.md | 18++++++++++++++++--
Asurf.suckless.org/files/feeds.md | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msurf.suckless.org/index.md | 13+++++++++++--
Msurf.suckless.org/patches/homepage.md | 1+
Asurf.suckless.org/patches/navigation-history.md | 19+++++++++++++++++++
Asurf.suckless.org/patches/omnibar.md | 32++++++++++++++++++++++++++++++++
Msurf.suckless.org/patches/searchengines.md | 5+++++
Msurf.suckless.org/patches/smoothscrolling-via-GTK3.md | 6+++---
Asurf.suckless.org/patches/surf-0.6-dmenu-unicode.diff | 26++++++++++++++++++++++++++
Msurf.suckless.org/patches/surf-0.6-homepage.diff | 27+++++++++++++++------------
Asurf.suckless.org/patches/surf-0.6-navhist.diff | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msurf.suckless.org/patches/surf-0.6-searchengines.diff | 80++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Asurf.suckless.org/patches/surf-0.7-omnibar.diff | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asurf.suckless.org/patches/surf-0.7-searchengines.diff | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asurf.suckless.org/patches/surf-0.7-smoothscrolling.diff | 238+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asurf.suckless.org/patches/surf-0.7-webkit2-searchengines.diff | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asurf.suckless.org/patches/surf-git-20160127-searchengines.diff | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asurf.suckless.org/patches/surf-tip-bookmarks.diff | 41+++++++++++++++++++++++++++++++++++++++++
Asurf.suckless.org/patches/surf-tip-navhist.diff | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asurf.suckless.org/patches/unicode-in-dmenu.md | 17+++++++++++++++++
Dsurf.suckless.org/stylesheets/startpage-dark.css | 110-------------------------------------------------------------------------------
Msurf.suckless.org/stylesheets/startpage.md | 16++++++++++------
Mtools.suckless.org/dmenu/index.md | 8+++++++-
Mtools.suckless.org/dmenu/patches/dmenu-4.5-fuzzymatch.diff | 102++++++++++++++++++++++++++++++++++++-------------------------------------------
Atools.suckless.org/dmenu/patches/dmenu-4.5-hide-single-newline.diff | 12++++++++++++
Atools.suckless.org/dmenu/patches/dmenu-4.5-xft-improved.diff | 425+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools.suckless.org/dmenu/patches/dmenu-4.6-line-height.diff | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools.suckless.org/dmenu/patches/dmenu-4.6-mouse-support-msel.diff | 154+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools.suckless.org/dmenu/patches/dmenu-4.6-vertfull.diff | 20++++++++++++++++++++
Atools.suckless.org/dmenu/patches/dmenu-4.6-xyw.diff | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools.suckless.org/dmenu/patches/dmenu-default-height.png | 0
Atools.suckless.org/dmenu/patches/dmenu-git-20151020-fuzzymatch.diff | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools.suckless.org/dmenu/patches/dmenu-git-20160111-hide-single-newline.diff | 12++++++++++++
Dtools.suckless.org/dmenu/patches/dmenu-git-fuzzymatch.diff | 143-------------------------------------------------------------------------------
Atools.suckless.org/dmenu/patches/dmenu-instant.diff | 38++++++++++++++++++++++++++++++++++++++
Atools.suckless.org/dmenu/patches/dmenu-line-height.png | 0
Mtools.suckless.org/dmenu/patches/fuzzymatch.md | 24+++++++++---------------
Atools.suckless.org/dmenu/patches/hide-single-newline.md | 19+++++++++++++++++++
Mtools.suckless.org/dmenu/patches/history.md | 8++++++++
Atools.suckless.org/dmenu/patches/instant.md | 12++++++++++++
Atools.suckless.org/dmenu/patches/line-height.md | 36++++++++++++++++++++++++++++++++++++
Atools.suckless.org/dmenu/patches/mouse-support-msel.md | 19+++++++++++++++++++
Atools.suckless.org/dmenu/patches/vertfull.md | 11+++++++++++
Mtools.suckless.org/dmenu/patches/xft.md | 1+
Mtools.suckless.org/dmenu/patches/xmms-like_pattern_matching.md | 2+-
Atools.suckless.org/dmenu/patches/xyw.md | 19+++++++++++++++++++
Atools.suckless.org/dmenu/scripts/dmenu_run_with_command_history/dmenu_run_history | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Atools.suckless.org/dmenu/scripts/dmenu_run_with_command_history/index.md | 23+++++++++++++++++++++++
Mtools.suckless.org/dmenu/scripts/index.md | 6++++++
Atools.suckless.org/dmenu/scripts/passmenu2 | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools.suckless.org/farbfeld/farbfeld.svg | 5+++++
Atools.suckless.org/farbfeld/index.md | 186+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools.suckless.org/farbfeld/invert.c | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dtools.suckless.org/lsx.md | 11-----------
Atools.suckless.org/sent/index.md | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools.suckless.org/sent/patches/index.md | 29+++++++++++++++++++++++++++++
Atools.suckless.org/sent/patches/toggle-mouse-cursor.diff | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools.suckless.org/sent/patches/toggle_cursor.md | 18++++++++++++++++++
Atools.suckless.org/sent/sent-bullets-s.png | 0
Atools.suckless.org/sent/sent-bullets.png | 0
Atools.suckless.org/sic/patches/lineprint.md | 24++++++++++++++++++++++++
Atools.suckless.org/sic/patches/sic-1.3-lineprint.diff | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Dtools.suckless.org/sic/patches/sic.1 | 57---------------------------------------------------------
Mtools.suckless.org/slock/index.md | 2+-
Mtools.suckless.org/slock/patches/capscolor.md | 8++++++--
Atools.suckless.org/slock/patches/slock-20160130-capscolor.diff | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dtools.suckless.org/ssid.md | 7-------
Mtools.suckless.org/tabbed/patches/clientnumber.md | 7++++---
Mtools.suckless.org/tabbed/patches/keycode.md | 7++++---
Dtools.suckless.org/tabbed/patches/tabbed-0.6-clientnumber.diff | 36------------------------------------
Atools.suckless.org/tabbed/patches/tabbed-0.6-xft.diff | 233+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools.suckless.org/tabbed/patches/tabbed-clientnumber-20160103-eb0ff62.patch | 23+++++++++++++++++++++++
Atools.suckless.org/tabbed/patches/tabbed-keycode-20160103-eb0ff62.patch | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools.suckless.org/tabbed/patches/xft.md | 18++++++++++++++++++
Rtools.suckless.org/lsw.md -> tools.suckless.org/x/lsw.md | 0
Rtools.suckless.org/sprop.md -> tools.suckless.org/x/sprop.md | 0
Rtools.suckless.org/sselp.md -> tools.suckless.org/x/sselp.md | 0
Rtools.suckless.org/svkbd.md -> tools.suckless.org/x/svkbd.md | 0
Rtools.suckless.org/swarp.md -> tools.suckless.org/x/swarp.md | 0
Rtools.suckless.org/wmname.md -> tools.suckless.org/x/wmname.md | 0
Rtools.suckless.org/xssstate.md -> tools.suckless.org/x/xssstate.md | 0
287 files changed, 14146 insertions(+), 6224 deletions(-)

diff --git a/dwm.suckless.org/dwmgetstatus.md b/dwm.suckless.org/dwmgetstatus.md @@ -9,8 +9,8 @@ Below is the script to do this: #!/bin/sh - xprop -root -f WM_NAME "8u" \ - | sed -n -r 's/WM_NAME\(STRING\) = \"(.*)\"/\1/p' + xprop -root -notype -f WM_NAME "8u" \ + | sed -n -r 's/WM_NAME = \"(.*)\"/\1/p' Link: [dwmgetstatus.sh](http://dwm.suckless.org/dwmgetstatus.sh) diff --git a/dwm.suckless.org/dwmgetstatus.sh b/dwm.suckless.org/dwmgetstatus.sh @@ -1,4 +1,4 @@ #!/bin/sh -xprop -root -f WM_NAME "8u" | sed -n -r 's/WM_NAME\(STRING\) = \"(.*)\"/\1/p' +xprop -root -notype -f WM_NAME "8u" | sed -n -r 's/WM_NAME = \"(.*)\"/\1/p' diff --git a/dwm.suckless.org/dwmstatus/dwmclock-netstat.c b/dwm.suckless.org/dwmstatus/dwmclock-netstat.c @@ -0,0 +1,140 @@ +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <time.h> +#include <locale.h> +#include <unistd.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <stdint.h> +#include <inttypes.h> +#include <math.h> + +#define IFNAMSIZ 16 + + +static const char* determine_def_if(void) { + FILE *f; + const char* ret = 0; + static char buf[IFNAMSIZ]; + char filebuf[256]; + f = fopen("/proc/net/route", "r"); + if (f) { + while (fgets(filebuf, sizeof filebuf, f)) { + char *tab = strchr(filebuf, '\t'); + if (tab && !strncmp(tab + 1, "00000000", 8)) { + memcpy(buf, filebuf, tab - filebuf); + buf[tab - filebuf] = 0; + ret = buf; + break; + } + } + fclose(f); + } + return ret; +} + +static uint64_t readfile(const char* filename) { + FILE* f; + uint64_t ret = 0, tmp; + f = fopen(filename, "r"); + if (f) { + if (fscanf(f, "%"SCNu64, &tmp) == 1) + ret = tmp; + fclose(f); + } + return ret; +} + +static uint64_t get_rx_bytes(const char* interface) +{ + char fnbuf[sizeof "/sys/class/net//statistics/rx_bytes" + IFNAMSIZ]; + strcpy(fnbuf, "/sys/class/net/"); + strcat(fnbuf, interface); + strcat(fnbuf, "/statistics/rx_bytes"); + return readfile(fnbuf); +} + +static uint64_t get_tx_bytes(const char* interface) +{ + char fnbuf[sizeof "/sys/class/net//statistics/rx_bytes" + IFNAMSIZ]; + strcpy(fnbuf, "/sys/class/net/"); + strcat(fnbuf, interface); + strcat(fnbuf, "/statistics/tx_bytes"); + return readfile(fnbuf); +} + +static int get_suff(uint64_t x) +{ + int r = -1 + !x; + while (x) { + r++; + x >>= 10; + } + return r; +} + +int main(void) { + Display *dpy; + Window root; + int loadfd; + + setlocale(LC_ALL, ""); + dpy = XOpenDisplay(0); + if (dpy) { + struct timespec tm, s; + ssize_t rv; + char oldif[IFNAMSIZ] = {0}; + uint64_t rxb, txb; + static const char suffixes[] = " KMGT"; // let's stay real here + root = XDefaultRootWindow(dpy); + clock_gettime(CLOCK_REALTIME, &tm); + s.tv_sec = 0; + s.tv_nsec = 1000000000 - tm.tv_nsec; + do rv = nanosleep(&s, &s); + while (rv == -1 && s.tv_nsec); + for (;;) { + char buf[100]; // estimate + const char *thisif = determine_def_if(); + uint64_t currxb, curtxb; + int idx; + int i; + if (thisif) + { + if (strcmp(thisif, oldif)) + { + strcpy(oldif, thisif); + rxb = txb = 0; + } + i = 0; + buf[i++] = oldif[0]; + buf[i++] = ' '; + buf[i++] = 'v'; + currxb = get_rx_bytes(oldif); + curtxb = get_tx_bytes(oldif); + idx = get_suff(currxb - rxb); + i += snprintf(buf + i, sizeof buf - i, "%.1f%c", (double)(currxb - rxb) / pow(1024, idx), suffixes[idx]); + rxb = currxb; + buf[i++] = ' '; + buf[i++] = '^'; + idx = get_suff(curtxb - txb); + i += snprintf(buf + i, sizeof buf - i, "%.1f%c", (double)(curtxb - txb) / pow(1024, idx), suffixes[idx]); + txb = curtxb; + } + else + buf[i++] = 'n'; + buf[i++] = ' '; + buf[i++] = '|'; + buf[i++] = ' '; + time_t t; + size_t l; + t = time(0); + l = strftime(buf + i, sizeof buf - i, "%c", localtime(&t)); + XStoreName(dpy, root, buf); + XSync(dpy, False); + sleep(1); + } + } +} diff --git a/dwm.suckless.org/dwmstatus/index.md b/dwm.suckless.org/dwmstatus/index.md @@ -22,10 +22,11 @@ Please add your own version of dwmstatus here. * [dwm-bar.c](https://github.com/wifiextender/dwm-bar) - Display overall usage about: cpu and cpu temperature, ram, disk, installed packages, kernel, motherboard voltage, system fans and their speed in RPM, motherboard (name, vendor, temperature), volume and time. I've wrote the code myself, so it is unique. * [dwmsd](https://github.com/johnko/dwmsd) - a daemon that listens on localhost tcp (may be useful as a base for asynchronous updates) * [profil-dwmstatus-1.0.c](profil-dwmstatus-1.0.c) - cpufreq, battery percent and date/time -* [suspend-statusbar.c](suspend-statusbar.c) - loadavg, wifi, battery and date. If battery goes below threshold - run suspend command +* [suspend-statusbar.c](https://github.com/akozadaev/dwm-statusbar) - loadavg, wifi, battery and date. If battery goes below threshold - run suspend command * [gods](https://github.com/schachmat/gods) - implemented in Go. prints network speed, cpu, ram, date/time * [go-dwmstatus](https://github.com/oniichaNj/go-dwmstatus) - A Go bar that prints current MPD song, load averages, time/date and battery percentage. * [barM](barM.c) - can display all, time/date, ram usage, output of commands (the New BarMonitor). +* [slstatus](https://github.com/drkh5h/slstatus) - *s*uck*l*ess *s*tatus - written in pure c without any system() - includes wifi percentage, battery, cpu usage and temperature, ram usage, alsa volume and time / date Helper functions ---------------- diff --git a/dwm.suckless.org/dwmstatus/profil-dwmstatus-1.0.c b/dwm.suckless.org/dwmstatus/profil-dwmstatus-1.0.c @@ -18,7 +18,7 @@ void setstatus(char *str) { float getfreq(char *file) { FILE *fd; - char *freq; + char *freq; float ret; freq = malloc(10); @@ -55,11 +55,11 @@ char *getdatetime() { fprintf(stderr, "strftime is 0.\n"); exit(1); } - + return buf; } -int getbattery() { +float getbattery() { FILE *fd; int energy_now, energy_full, voltage_now; @@ -107,14 +107,14 @@ int main(void) { if((status = malloc(200)) == NULL) exit(1); - + for (;;sleep(1)) { cpu0 = getfreq("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"); cpu1 = getfreq("/sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq"); datetime = getdatetime(); bat0 = getbattery(); - snprintf(status, 200, "%0.2f, %0.2f | %d%% | %s", cpu0, cpu1, bat0, datetime); + snprintf(status, 200, "%0.2f, %0.2f | %.2lf%% | %s", cpu0, cpu1, bat0, datetime); free(datetime); setstatus(status); diff --git a/dwm.suckless.org/dwmstatus/suspend-statusbar.c b/dwm.suckless.org/dwmstatus/suspend-statusbar.c @@ -1,219 +0,0 @@ -/* statusbar.c */ -/* Copyright (C) 2012 Alex Kozadaev [akozadaev at yahoo com] */ -/* git clone git@github.com:akozadaev/dwm-statusbar.git */ - -#include "build_host.h" - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <time.h> -#include <signal.h> -#include <X11/Xlib.h> - -/* =================================================================== -autoconfiguration - snippet from Makefile - -BATPATH=`find /sys -name BAT0 -print0 -quit` -LNKPATH=`find /sys/class/net/wlan0/ -name operstate -print0 -quit` -LAPATH=`find /proc -name loadavg -print0 -quit` - -# git@github.com:akozadaev/boxsuspend.git -BOXSUSPEND=`which boxsuspend` - - -build_host.h: - @echo "#define BUILD_HOST \"`hostname`\"" > build_host.h - @echo "#define BUILD_OS \"`uname`\"" >> build_host.h - @echo "#define BUILD_PLATFORM \"`uname -m`\"" >> build_host.h - @echo "#define BUILD_KERNEL \"`uname -r`\"" >> build_host.h - @echo "#define LA_PATH \"${LAPATH}\"" >> build_host.h - @echo "#define BAT_NOW \"${BATPATH}/charge_now\"" >> build_host.h - @echo "#define BAT_FULL \"${BATPATH}/charge_full\"" >> build_host.h - @echo "#define BAT_STAT \"${BATPATH}/status\"" >> build_host.h - @echo "#define LNK_PATH \"${LNKPATH}\"" >> build_host.h - @echo "#define BOX_SUSPEND \"${BOXSUSPEND}\"" >> build_host.h -=================================================================== */ - -/* version 0.64 */ - -#define THRESHOLD 8 -#define TIMEOUT 40 -#define SUSPEND { BOX_SUSPEND, NULL } /* BOX_SUSPEND gets configured in Makefile */ - -#define LABUF 14 -#define DTBUF 20 -#define LNKBUF 8 -#define STR 64 - -/* Available statuses - * - * Charging - * Discharging - * Unknown - * Full - */ -typedef enum { - C, D, U, F -} status_t; - - -static void spawn(const char **params) __attribute__ ((unused)); -static void set_status(char *str); -static void open_display(void) __attribute__ ((unused)); -static void close_display() __attribute__ ((unused)); -static void get_datetime(char *buf); -static status_t get_status(); -static int read_int(const char *path); -static void read_str(const char *path, char *buf, size_t sz); - -static Display *dpy; - -int -main(void) -{ - int timer = 0; - float bat; /* battery status */ - char lnk[STR] = { 0 }; /* wifi link */ - char la[STR] = { 0 }; /* load average */ - char dt[STR] = { 0 }; /* date/time */ - char stat[STR] = { 0 }; /* full string */ - status_t st; /* battery status */ - char status[] = { '+', '-', '?', '=' }; /* should be the same order as the enum above (C, D, U, F) */ - -#ifndef DEBUG - open_display(); -#endif - - while (!sleep(1)) { - read_str(LA_PATH, la, LABUF); /* load average */ - read_str(LNK_PATH, lnk, LNKBUF); /* link status */ - get_datetime(dt); /* date/time */ - bat = ((float)read_int(BAT_NOW) / - read_int(BAT_FULL)) * 100.0f; /* battery */ - st = get_status(); /* battery status (charging/discharging/full/etc) */ - - if (st == D && bat < THRESHOLD) { - snprintf(stat, STR, "LOW BATTERY: suspending after %d ", TIMEOUT - timer); - set_status(stat); - if (timer >= TIMEOUT) { -#ifndef DEBUG - spawn((const char*[])SUSPEND); -#else - puts("sleeping"); -#endif - timer = 0; - } else - timer++; - } else { - snprintf(stat, STR, "%s | %s | %c%0.1f%% | %s", la, lnk, status[st], - (bat > 100) ? 100 : bat, dt); - set_status(stat); - timer = 0; /* reseting the standby timer */ - } - } - -#ifndef DEBUG - close_display(); -#endif - return 0; -} - -static void -spawn(const char **params) { - if (fork() == 0) { - setsid(); - execv(params[0], (char**)params); - exit(0); - } -} - -static void -set_status(char *str) -{ -#ifndef DEBUG - XStoreName(dpy, DefaultRootWindow(dpy), str); - XSync(dpy, False); -#else - puts(str); -#endif -} - -static void -open_display(void) -{ - if (!(dpy = XOpenDisplay(NULL))) - exit(1); - signal(SIGINT, close_display); - signal(SIGTERM, close_display); -} - -static void -close_display() -{ - XCloseDisplay(dpy); - exit(0); -} - -static void -get_datetime(char *buf) -{ - time_t rawtime; - time(&rawtime); - snprintf(buf, DTBUF, "%s", ctime(&rawtime)); -} - -static status_t -get_status() -{ - FILE *bs; - char st; - - if ((bs = fopen(BAT_STAT, "r")) == NULL) - return U; - - st = fgetc(bs); - fclose(bs); - - switch(st) { - case 'C': return C; /* Charging */ - case 'D': return D; /* Discharging */ - case 'F': return F; /* Full */ - default : return U; /* Unknown */ - } -} - -static int -read_int(const char *path) -{ - int i = 0; - FILE *fh; - - if (!(fh = fopen(path, "r"))) - return -1; - - fscanf(fh, "%d", &i); - fclose(fh); - return i; -} - -static void -read_str(const char *path, char *buf, size_t sz) -{ - FILE *fh; - char ch = 0; - int idx = 0; - - if (!(fh = fopen(path, "r"))) return; - - while ((ch = fgetc(fh)) != EOF && ch != '\0' && ch != '\n' && idx < sz) { - buf[idx++] = ch; - } - - buf[idx] = '\0'; - fclose(fh); -} - -/* EOF */ - diff --git a/dwm.suckless.org/index.md b/dwm.suckless.org/index.md @@ -51,7 +51,7 @@ Links Download -------- * [MIT/X Consortium license](http://git.suckless.org/dwm/plain/LICENSE) -* [dwm 6.0](http://dl.suckless.org/dwm/dwm-6.0.tar.gz) (20kb) (20111219) +* [dwm 6.1](http://dl.suckless.org/dwm/dwm-6.1.tar.gz) (25kb) (20151109) * See also [dmenu](http://tools.suckless.org/dmenu) Support diff --git a/dwm.suckless.org/patches/ansistatuscolors.md b/dwm.suckless.org/patches/ansistatuscolors.md @@ -2,7 +2,7 @@ ## Description ## -Lets you put colored text in your status bar, but you don''t have define them in your config.h. Instead, just put the ansi escape sequence in the output of your status bar script to print in color, as you would in a terminal. +Lets you put colored text in your status bar, but you don't have define them in your config.h. Instead, just put the ansi escape sequence in the output of your status bar script to print in color, as you would in a terminal. ## Configuration ## @@ -14,7 +14,7 @@ apply it to dwm.c like so: ## Usage ## -Just like you''d use them for colorizing a shell script. +Just like you'd use them for colorizing a shell script. more info is here: [http://www.frexx.de/xterm-256-notes/](http://www.frexx.de/xterm-256-notes/) @@ -55,8 +55,8 @@ the code is one of the following: 16-231 - xterm 256-color rgb color 232-255 - grayscale -in vim, to create a literal 'escape' character, type ctrl-v, esc. -in perl/python/c, within a string literal, it''s "\x1b". +in vim, to create a literal 'escape' character, type ctrl-v, esc. +in perl/python/c, within a string literal, it's "\x1b". ### Example ### #!/usr/bin/env python diff --git a/dwm.suckless.org/patches/attachabove.md b/dwm.suckless.org/patches/attachabove.md @@ -11,10 +11,10 @@ Download Patches against different versions of dwm are available at [dwm-clean-patches](https://github.com/jceb/dwm-clean-patches). - * [dwm-6.1-attachabove.diff](dwm-6.1-attachabove.diff) (1786b) (20140209) - * [dwm-10e232f9ace7-attachabove.diff](dwm-10e232f9ace7-attachabove.diff) (1709b) (20120406) + * [dwm-6.1-attachabove.diff](dwm-6.1-attachabove.diff) (1829b) (20151122) + * [dwm-git-20120406-attachabove.diff](dwm-git-20120406-attachabove.diff) (1709b) * [dwm-6.0-attachabove.diff](dwm-6.0-attachabove.diff) (1707b) (20120406) - * [dwm-5.6.1-attachabove.diff](dwm-5.6.1-attachabove.diff) (1.1K) (20090817) + * [dwm-5.6.1-attachabove.diff](historical/dwm-5.6.1-attachabove.diff) (1.1K) (20090817) Author ------ diff --git a/dwm.suckless.org/patches/attachaside.md b/dwm.suckless.org/patches/attachaside.md @@ -12,7 +12,7 @@ area instead of always becoming the new master. It's basically an | | | | | P | | | | - | N +-------| + | N +-------+ | | | | | | | | | @@ -55,8 +55,8 @@ improved to also attach to the stack on unfocused tags. ### Original * [dwm-6.0-attachaside.diff](dwm-6.0-attachaside.diff) (1,6K) (20140412) -* [dwm-5.7.2-attachaside.diff](dwm-5.7.2-attachaside.diff) (1.1K) (20091215) -* [dwm-5.6.1-attachaside.diff](dwm-5.6.1-attachaside.diff) (1.1K) (20090915) +* [dwm-5.7.2-attachaside.diff](historical/dwm-5.7.2-attachaside.diff) (1.1K) (20091215) +* [dwm-5.6.1-attachaside.diff](historical/dwm-5.6.1-attachaside.diff) (1.1K) (20090915) Authors ------- diff --git a/dwm.suckless.org/patches/better-borders.md b/dwm.suckless.org/patches/better-borders.md @@ -12,10 +12,13 @@ as the monitor and marks them full-screen even if their X properties indicate otherwise. This eliminates nuisance borders that appear with some games and applications while in full-screen mode. +Thanks to Alesandar Metodiev for reporting a bug that lead to the patch being +rewritten. + Download -------- - * [dwm-6.1-better-borders.diff](dwm-6.1-better-borders.diff) (2014-07-13) + * [dwm-6.1-better-borders.diff](dwm-6.1-better-borders.diff) (2015-12-27) Author ------ diff --git a/dwm.suckless.org/patches/center.md b/dwm.suckless.org/patches/center.md @@ -10,7 +10,8 @@ monitor. Download -------- -* [dwm-cdec978-center.diff](dwm-cdec978-center.diff) (2k) (20140123) +* [dwm-6.1-center.diff](dwm-6.1-center.diff) (2k) (20151114) +* [dwm-cdec978-center.diff](historical/dwm-cdec978-center.diff) (2k) (20140123) Author ------ diff --git a/dwm.suckless.org/patches/centeredmaster.c b/dwm.suckless.org/patches/centeredmaster.c @@ -0,0 +1,91 @@ +void +centeredfloatingmaster(Monitor *m) { + unsigned int i, n, w, mh, mw, mx, mxo, my, myo, tx; + Client *c; + + // Count number of clients in the selected monitor + for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if(n == 0) + return; + + // initialize nmaster area + if(n > m->nmaster) { + // go mfact box in the center if more than nmaster clients + if(m->ww > m->wh) { + mw = m->nmaster ? m->ww * m->mfact : 0; + mh = m->nmaster ? m->wh * 0.9 : 0; + } else { + mh = m->nmaster ? m->wh * m->mfact : 0; + mw = m->nmaster ? m->ww * 0.9 : 0; + } + mx = mxo = (m->ww - mw) / 2; + my = myo = (m->wh - mh) / 2; + } else { + // Go fullscreen if all clients are in the master area + mh = m->wh; + mw = m->ww; + mx = mxo = 0; + my = myo = 0; + } + for(i = tx = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if(i < m->nmaster) { + // nmaster clients are stacked horizontally, in the center of the screen + w = (mw + mxo - mx) / (MIN(n, m->nmaster) - i); + resize(c, m->wx + mx, m->wy + my, w - (2*c->bw), mh - (2*c->bw), False); + mx += WIDTH(c); + } else { + // Stack clients are stacked horizontally + w = (m->ww - tx) / (n - i); + resize(c, m->wx + tx, m->wy, w - (2*c->bw), m->wh - (2*c->bw), False); + tx += WIDTH(c); + } +} + +void +centeredmaster(Monitor *m) { + unsigned int i, n, h, mw, mx, my, oty, ety, tw; + Client *c; + + // Count number of clients in the selected monitor + for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if(n == 0) + return; + + // initialize areas + mw = m->ww; + mx = 0; + my = 0; + tw = mw; + + if(n > m->nmaster) { + // go mfact box in the center if more than nmaster clients + mw = m->nmaster ? m->ww * m->mfact : 0; + tw = m->ww - mw; + + if (n - m->nmaster > 1) { // only one client + mx = (m->ww - mw) / 2; + tw = (m->ww - mw) / 2; + } + } + + oty = 0; + ety = 0; + for(i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if(i < m->nmaster) { + // nmaster clients are stacked verticaly, in the center of the screen + h = (m->wh - my) / (MIN(n, m->nmaster) - i); + resize(c, m->wx + mx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False); + my += HEIGHT(c); + } else { + // Stack clients are stacked verticaly + if ((i - m->nmaster) % 2 ) { + h = (m->wh - ety) / ( (1 + n - i) / 2); + resize(c, m->wx, m->wy + ety, tw - (2*c->bw), h - (2*c->bw), False); + ety += HEIGHT(c); + } else { + h = (m->wh - oty) / ((1 + n - i) / 2); + resize(c, m->wx + mx + mw, m->wy + oty, tw - (2*c->bw), h - (2*c->bw), False); + oty += HEIGHT(c); + } + } +} diff --git a/dwm.suckless.org/patches/centeredmaster.md b/dwm.suckless.org/patches/centeredmaster.md @@ -1,19 +1,47 @@ # centeredmaster -`centeredmaster` layout patch makes the nmaster area centered -on screen, using `mfact * monitor width & height`, over an -horizontally tiled `stack` area, pretty much like -a "scratchpad". +## `centeredmaster` -I find it useful on large screens (say 1920px wide), where -`monocle` or `htile` feels either too large or makes me type in -a corner of the screen. +makes the nmaster area centered +on screen, using `mfact * monitor width & height`, with the stacked windows +distributed on left and right. -With `centeredmaster`, for instance, I can set my editor in the -center, while keeping an eye on what's happening in the windows -behind (logs, tests, ...). +With one client in master: + +------------------------------+ + |+--------++--------++--------+| + || || || || + || || || || + || || || || + || S2 || M || S1 || + || || || || + || || || || + || || || || + || || || || + |+--------++--------++--------+| + +------------------------------+ +With two clients in master: + + +------------------------------+ + |+--------++--------++--------+| + || || || || + || || M1 || || + || || || || + || |+--------+| || + || |+--------+| || + || || || || + || || M2 || || + || || || || + |+--------++--------++--------+| + +------------------------------+ + +## `centeredfloatingmaster` + +makes the nmaster area centered +on screen, using `mfact * monitor width & height`, over an +horizontally tiled `stack` area, pretty much like +a "scratchpad". With one client in master: @@ -46,19 +74,21 @@ With two clients in master: +------------------------------+ -## Links - -* [dwm-6.1-centeredmaster.diff](dwm-6.1-centeredmaster.diff) - 4K, 2015/08/15 - - -[jerome](http://blog.jardinmagique.info) <jerome@gcu.info> - - +I find it useful on large screens (say 1920px wide), where +`monocle` or `htile` feels either too large or makes me type in +a corner of the screen. +With `centeredmaster`, for instance, I can set my editor in the +center, while keeping an eye on what's happening in the windows +behind (logs, tests, ...). +## Links +* [centeredmaster.c](centeredmaster.c) - 2015/11/22 +* [dwm-6.1-centeredmaster.diff](dwm-6.1-centeredmaster.diff) - 2015/11/21 +[jerome](http://blog.jardinmagique.info) <jerome@gcu.info> diff --git a/dwm.suckless.org/patches/combo.md b/dwm.suckless.org/patches/combo.md @@ -18,11 +18,13 @@ and view so you could replace all usages if you wanted. Download -------- - * [dwm-5.9-combo.diff](dwm-5.9-combo.diff) (2010-10-30) - * [dwm-6.0-combo.diff](dwm-6.0-combo.diff) (2012-10-09) + * [dwm-5.9-combo.diff](dwm-5.9-combo.diff) - 2010-10-30 + * [dwm-6.0-combo.diff](dwm-6.0-combo.diff) - 2012-10-09 + * [dwm-6.1-combo.diff](dwm-6.1-combo.diff) - 2016-01-22 Author ------ * Wolf Tivy - wolf at tivy dot com. * Dan McNair - cosfx at h0v3 dot net (mechanical update to 6.0) + * Matthew Boswell - mordervomubel+suckless at lockmail dot us (mechanical update to 6.1) diff --git a/dwm.suckless.org/patches/dualstatus.md b/dwm.suckless.org/patches/dualstatus.md @@ -11,7 +11,7 @@ xsetroot -name "top text;bottom text" Download -------- - * [dwm-6.1-dualstatus.diff](dwm-6.1-dualstatus.diff) (4688b) (20130908) + * [dwm-6.1-dualstatus.diff](dwm-6.1-dualstatus.diff) (4683b) (20151110) * [dwm-6.0-dualstatus.diff](dwm-6.0-dualstatus.diff) (4794b) (20130908) Screenshot diff --git a/dwm.suckless.org/patches/dwm-10e232f9ace7-push.diff b/dwm.suckless.org/patches/dwm-10e232f9ace7-push.diff @@ -1,65 +0,0 @@ -URL: http://dwm.suckless.org/patches/push -pushup and pushdown provide a way to move clients inside the clients list. - -diff -r 10e232f9ace7 push.c ---- /dev/null Thu Jan 01 00:00:00 1970 +0000 -+++ b/push.c Fri Apr 06 08:16:39 2012 +0200 -@@ -0,0 +1,58 @@ -+static Client * -+prevtiled(Client *c) { -+ Client *p, *r; -+ -+ for(p = selmon->clients, r = NULL; p && p != c; p = p->next) -+ if(!p->isfloating && ISVISIBLE(p)) -+ r = p; -+ return r; -+} -+ -+static void -+pushup(const Arg *arg) { -+ Client *sel = selmon->sel; -+ Client *c; -+ -+ if(!sel || sel->isfloating) -+ return; -+ if((c = prevtiled(sel))) { -+ /* attach before c */ -+ detach(sel); -+ sel->next = c; -+ if(selmon->clients == c) -+ selmon->clients = sel; -+ else { -+ for(c = selmon->clients; c->next != sel->next; c = c->next); -+ c->next = sel; -+ } -+ } else { -+ /* move to the end */ -+ for(c = sel; c->next; c = c->next); -+ detach(sel); -+ sel->next = NULL; -+ c->next = sel; -+ } -+ focus(sel); -+ arrange(selmon); -+} -+ -+static void -+pushdown(const Arg *arg) { -+ Client *sel = selmon->sel; -+ Client *c; -+ -+ if(!sel || sel->isfloating) -+ return; -+ if((c = nexttiled(sel->next))) { -+ /* attach after c */ -+ detach(sel); -+ sel->next = c->next; -+ c->next = sel; -+ } else { -+ /* move to the front */ -+ detach(sel); -+ attach(sel); -+ } -+ focus(sel); -+ arrange(selmon); -+} diff --git a/dwm.suckless.org/patches/dwm-14343e69cc59-systray.diff b/dwm.suckless.org/patches/dwm-14343e69cc59-systray.diff @@ -1,687 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index eaae8f3..42f4165 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -15,6 +15,10 @@ static const char selbgcolor[] = "#005577"; - static const char selfgcolor[] = "#eeeeee"; - static const unsigned int borderpx = 1; /* border pixel of windows */ - static const unsigned int snap = 32; /* snap pixel */ -+static const 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 Bool systraypinningfailfirst = True; /* True: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ -+static const Bool showsystray = True; /* False means no systray */ - static const Bool showbar = True; /* False means no bar */ - static const Bool topbar = True; /* False means bottom bar */ - -diff --git a/dwm.c b/dwm.c -index 169adcb..859143e 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -57,12 +57,30 @@ - #define TAGMASK ((1 << LENGTH(tags)) - 1) - #define TEXTW(X) (drw_text(drw, 0, 0, 0, 0, (X), 0) + drw->fonts[0]->h) - -+#define SYSTEM_TRAY_REQUEST_DOCK 0 -+#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0 -+ -+/* XEMBED messages */ -+#define XEMBED_EMBEDDED_NOTIFY 0 -+#define XEMBED_WINDOW_ACTIVATE 1 -+#define XEMBED_FOCUS_IN 4 -+#define XEMBED_MODALITY_ON 10 -+ -+#define XEMBED_MAPPED (1 << 0) -+#define XEMBED_WINDOW_ACTIVATE 1 -+#define XEMBED_WINDOW_DEACTIVATE 2 -+ -+#define VERSION_MAJOR 0 -+#define VERSION_MINOR 0 -+#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR -+ - /* enums */ - enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ - enum { SchemeNorm, SchemeSel, SchemeLast }; /* color schemes */ --enum { NetSupported, NetWMName, NetWMState, -- NetWMFullscreen, NetActiveWindow, NetWMWindowType, -- NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ -+enum { NetSupported, NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, -+ NetWMName, NetWMState, 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 Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact); -@@ -170,8 +194,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 Bool getrootptr(int *x, int *y); - static long getstate(Window w); -+static unsigned int getsystraywidth(); - static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); - static void grabbuttons(Client *c, Bool focused); - static void grabkeys(void); -@@ -189,13 +215,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, Bool 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 Bool sendevent(Client *c, Atom proto); -+static Bool 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 setup(void); - 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,24 @@ static void updateclientlist(void); - static void updatenumlockmask(void); - static void updatesizehints(Client *c); - static void updatestatus(void); -+static void updatesystray(void); -+static void updatesystrayicongeom(Client *i, int w, int h); -+static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); - static void updatewindowtype(Client *c); - static void updatetitle(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 unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ; - static const char broken[] = "broken"; - static char stext[256]; - static int screen; -@@ -256,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 Bool running = True; - static Cur *cursor[CurLast]; - static ClrScheme scheme[SchemeLast]; -@@ -471,6 +508,11 @@ cleanup(void) { - XUngrabKey(dpy, AnyKey, AnyModifier, root); - while(mons) - cleanupmon(mons); -+ if(showsystray) { -+ XUnmapWindow(dpy, systray->win); -+ XDestroyWindow(dpy, systray->win); -+ free(systray); -+ } - drw_cur_free(drw, cursor[CurNormal]); - drw_cur_free(drw, cursor[CurResize]); - drw_cur_free(drw, cursor[CurMove]); -@@ -515,9 +557,49 @@ clearurgent(Client *c) { - - 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)); -+ c->win = cme->data.l[2]; -+ c->mon = selmon; -+ c->next = systray->icons; -+ systray->icons = c; -+ XGetWindowAttributes(dpy, c->win, &wa); -+ c->x = c->oldx = c->y = c->oldy = 0; -+ c->w = c->oldw = wa.width; -+ c->h = c->oldh = wa.height; -+ c->oldbw = wa.border_width; -+ c->bw = 0; -+ c->isfloating = True; -+ /* reuse tags field as mapped status */ -+ c->tags = 1; -+ updatesizehints(c); -+ updatesystrayicongeom(c, wa.width, wa.height); -+ XAddToSaveSet(dpy, c->win); -+ XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); -+ XReparentWindow(dpy, c->win, systray->win, 0, 0); -+ /* use parents background color */ -+ swa.background_pixel = scheme[SchemeNorm].bg->pix; -+ 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 +649,7 @@ configurenotify(XEvent *e) { - drw_resize(drw, sw, bh); - updatebars(); - for(m = mons; m; m = m->next) -- XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); -+ resizebarwin(m); - focus(NULL); - arrange(NULL); - } -@@ -651,6 +733,11 @@ destroynotify(XEvent *e) { - - if((c = wintoclient(ev->window))) - unmanage(c, True); -+ else if((c = wintosystrayicon(ev->window))) { -+ removesystrayicon(c); -+ resizebarwin(selmon); -+ updatesystray(); -+ } - } - - void -@@ -695,6 +782,7 @@ drawbar(Monitor *m) { - unsigned int i, occ = 0, urg = 0; - Client *c; - -+ resizebarwin(m); - for(c = m->clients; c; c = c->next) { - occ |= c->tags; - if(c->isurgent) -@@ -717,6 +805,9 @@ drawbar(Monitor *m) { - if(m == selmon) { /* status is only drawn on selected monitor */ - w = TEXTW(stext); - x = m->ww - w; -+ if(showsystray && m == systraytomon(m)) { -+ x -= getsystraywidth(); -+ } - if(x < xx) { - x = xx; - w = m->ww - xx; -@@ -746,6 +837,7 @@ drawbars(void) { - - for(m = mons; m; m = m->next) - drawbar(m); -+ updatesystray(); - } - - void -@@ -772,8 +864,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 -@@ -856,10 +951,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; -@@ -891,6 +993,15 @@ 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; -+} -+ - Bool - gettextprop(Window w, Atom atom, char *text, unsigned int size) { - char **list = NULL; -@@ -991,7 +1102,7 @@ void - 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); -@@ -1077,6 +1188,12 @@ 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; -@@ -1198,6 +1315,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) -@@ -1247,12 +1374,33 @@ recttomon(int x, int y, int w, int h) { - } - - 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, Bool 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; - -@@ -1323,6 +1471,18 @@ 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) { - Client *c; - XEvent ev; -@@ -1406,25 +1566,35 @@ setclientstate(Client *c, long state) { - } - - Bool --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; - Bool exists = False; - 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; - } -@@ -1437,7 +1607,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 -@@ -1520,12 +1690,18 @@ 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[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); - netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", 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); -@@ -1537,6 +1713,8 @@ setup(void) { - scheme[SchemeSel].border = drw_clr_create(drw, selbordercolor); - scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor); - scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor); -+ /* init system tray */ -+ updatesystray(); - /* init bars */ - updatebars(); - updatestatus(); -@@ -1592,6 +1770,22 @@ spawn(const Arg *arg) { - } - } - -+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 - tag(const Arg *arg) { - if(selmon->sel && arg->ui & TAGMASK) { -@@ -1638,7 +1832,18 @@ void - 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); - } - -@@ -1728,11 +1933,18 @@ unmapnotify(XEvent *e) { - else - unmanage(c, False); - } -+ else if((c = wintosystrayicon(ev->window))) { -+ removesystrayicon(c); -+ resizebarwin(selmon); -+ updatesystray(); -+ } - } - - void - updatebars(void) { -+ unsigned int w; - Monitor *m; -+ - XSetWindowAttributes wa = { - .override_redirect = True, - .background_pixmap = ParentRelative, -@@ -1741,10 +1953,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); - } - } -@@ -1938,6 +2155,117 @@ updatestatus(void) { - } - - 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 dimenons 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].bg->pix); -+ wa.event_mask = ButtonPressMask | ExposureMask; -+ wa.override_redirect = True; -+ wa.background_pixel = scheme[SchemeNorm].bg->pix; -+ XSelectInput(dpy, systray->win, SubstructureNotifyMask); -+ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, -+ PropModeReplace, (unsigned char *)&systrayorientation, 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].bg->pix; -+ 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].bg->pix); -+ XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); -+ XSync(dpy, False); -+} -+ -+void - updatewindowtype(Client *c) { - Atom state = getatomprop(c, netatom[NetWMState]); - Atom wtype = getatomprop(c, netatom[NetWMWindowType]); -@@ -2006,6 +2334,16 @@ wintomon(Window w) { - return selmon; - } - -+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; -+} -+ - /* There's no way to check accesses to destroyed windows, thus those cases are - * ignored (especially on UnmapNotify's). Other types of errors call Xlibs - * default error handler, which may call exit. */ diff --git a/dwm.suckless.org/patches/dwm-20151110-5ed9c48-keycode.patch b/dwm.suckless.org/patches/dwm-20151110-5ed9c48-keycode.patch @@ -0,0 +1,146 @@ +From 6a9c5bc422a68a40d5eb2b873fa01d59d6c5bd50 Mon Sep 17 00:00:00 2001 +From: Quentin Rameau <quinq@fifth.space> +Date: Tue, 10 Nov 2015 19:09:20 +0100 +Subject: [PATCH] Use keycodes instead of keysyms + +--- + config.def.h | 68 ++++++++++++++++++++++++++++++------------------------------ + dwm.c | 15 +++++--------- + 2 files changed, 39 insertions(+), 44 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 7054c06..f59d1eb 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -58,40 +58,40 @@ static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, + static const char *termcmd[] = { "st", NULL }; + + static Key keys[] = { +- /* modifier key function argument */ +- { MODKEY, XK_p, spawn, {.v = dmenucmd } }, +- { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, +- { MODKEY, XK_b, togglebar, {0} }, +- { MODKEY, XK_j, focusstack, {.i = +1 } }, +- { MODKEY, XK_k, focusstack, {.i = -1 } }, +- { MODKEY, XK_i, incnmaster, {.i = +1 } }, +- { MODKEY, XK_d, incnmaster, {.i = -1 } }, +- { MODKEY, XK_h, setmfact, {.f = -0.05} }, +- { MODKEY, XK_l, setmfact, {.f = +0.05} }, +- { MODKEY, XK_Return, zoom, {0} }, +- { MODKEY, XK_Tab, view, {0} }, +- { MODKEY|ShiftMask, XK_c, killclient, {0} }, +- { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, +- { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, +- { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, +- { MODKEY, XK_space, setlayout, {0} }, +- { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, +- { MODKEY, XK_0, view, {.ui = ~0 } }, +- { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, +- { MODKEY, XK_comma, focusmon, {.i = -1 } }, +- { MODKEY, XK_period, focusmon, {.i = +1 } }, +- { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, +- { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, +- TAGKEYS( XK_1, 0) +- TAGKEYS( XK_2, 1) +- TAGKEYS( XK_3, 2) +- TAGKEYS( XK_4, 3) +- TAGKEYS( XK_5, 4) +- TAGKEYS( XK_6, 5) +- TAGKEYS( XK_7, 6) +- TAGKEYS( XK_8, 7) +- TAGKEYS( XK_9, 8) +- { MODKEY|ShiftMask, XK_q, quit, {0} }, ++ /* modifier key function argument */ ++ { MODKEY, 33, spawn, {.v = dmenucmd } }, // p ++ { MODKEY|ShiftMask, 36, spawn, {.v = termcmd } }, // Return ++ { MODKEY, 56, togglebar, {0} }, // b ++ { MODKEY, 44, focusstack, {.i = +1 } }, // j ++ { MODKEY, 45, focusstack, {.i = -1 } }, // k ++ { MODKEY, 31, incnmaster, {.i = +1 } }, // i ++ { MODKEY, 40, incnmaster, {.i = -1 } }, // d ++ { MODKEY, 43, setmfact, {.f = -0.05} }, // h ++ { MODKEY, 46, setmfact, {.f = +0.05} }, // l ++ { MODKEY, 36, zoom, {0} }, // Return ++ { MODKEY, 23, view, {0} }, // Tab ++ { MODKEY|ShiftMask, 54, killclient, {0} }, // c ++ { MODKEY, 28, setlayout, {.v = &layouts[0]} }, // t ++ { MODKEY, 41, setlayout, {.v = &layouts[1]} }, // f ++ { MODKEY, 58, setlayout, {.v = &layouts[2]} }, // m ++ { MODKEY, 65, setlayout, {0} }, // space ++ { MODKEY|ShiftMask, 65, togglefloating, {0} }, // space ++ { MODKEY, 19, view, {.ui = ~0 } }, // 0 ++ { MODKEY|ShiftMask, 19, tag, {.ui = ~0 } }, // 0 ++ { MODKEY, 59, focusmon, {.i = -1 } }, // comma ++ { MODKEY, 60, focusmon, {.i = +1 } }, // period ++ { MODKEY|ShiftMask, 59, tagmon, {.i = -1 } }, // comma ++ { MODKEY|ShiftMask, 60, tagmon, {.i = +1 } }, // period ++ TAGKEYS( 10, 0) // 1 ++ TAGKEYS( 11, 1) // 2 ++ TAGKEYS( 12, 2) // 3 ++ TAGKEYS( 13, 3) // 4 ++ TAGKEYS( 14, 4) // 5 ++ TAGKEYS( 15, 5) // 6 ++ TAGKEYS( 16, 6) // 7 ++ TAGKEYS( 17, 7) // 8 ++ TAGKEYS( 18, 8) // 9 ++ { MODKEY|ShiftMask, 24, quit, {0} }, // q + }; + + /* button definitions */ +diff --git a/dwm.c b/dwm.c +index 0362114..60dd817 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -31,7 +31,6 @@ + #include <sys/types.h> + #include <sys/wait.h> + #include <X11/cursorfont.h> +-#include <X11/keysym.h> + #include <X11/Xatom.h> + #include <X11/Xlib.h> + #include <X11/Xproto.h> +@@ -101,7 +100,7 @@ struct Client { + + typedef struct { + unsigned int mod; +- KeySym keysym; ++ KeyCode keycode; + void (*func)(const Arg *); + const Arg arg; + } Key; +@@ -967,14 +966,12 @@ grabkeys(void) + { + 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); ++ for (j = 0; j < LENGTH(modifiers); j++) ++ XGrabKey(dpy, keys[i].keycode, keys[i].mod | modifiers[j], root, ++ True, GrabModeAsync, GrabModeAsync); + } + } + +@@ -1001,13 +998,11 @@ 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 ++ if (ev->keycode == keys[i].keycode + && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) + && keys[i].func) + keys[i].func(&(keys[i].arg)); +-- +2.6.2 + diff --git a/dwm.suckless.org/patches/dwm-3465bed290ab-maximize_vert_horz.diff b/dwm.suckless.org/patches/dwm-3465bed290ab-maximize_vert_horz.diff @@ -0,0 +1,73 @@ +Author: Jan Christoph Ebersbach <jceb@e-jc.de> +URL: http://dwm.suckless.org/patches/historical/moveresize +These patches provide helper functions for moving and resizing floating windows +using keybindings. + +Index: dwm/dwm.c +=================================================================== +--- dwm/dwm.c.orig 2014-02-09 15:24:12.552116979 +0100 ++++ dwm/dwm.c 2014-02-09 15:24:12.548116979 +0100 +@@ -92,7 +92,7 @@ + int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int bw, oldbw; + unsigned int tags; +- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; ++ int ismax, wasfloating, isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; + Client *next; + Client *snext; + Monitor *mon; +@@ -1077,6 +1077,8 @@ + updatewmhints(c); + XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); + grabbuttons(c, 0); ++ c->wasfloating = 0; ++ c->ismax = 0; + if (!c->isfloating) + c->isfloating = c->oldstate = trans != None || c->isfixed; + if (c->isfloating) +Index: dwm/maximize.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ dwm/maximize.c 2014-02-09 15:24:12.548116979 +0100 +@@ -0,0 +1,41 @@ ++void ++maximize(int x, int y, int w, int h) { ++ XEvent ev; ++ ++ if(!selmon->sel || selmon->sel->isfixed) ++ return; ++ XRaiseWindow(dpy, selmon->sel->win); ++ if(!selmon->sel->ismax) { ++ if(!selmon->lt[selmon->sellt]->arrange || selmon->sel->isfloating) ++ selmon->sel->wasfloating = 1; ++ else { ++ togglefloating(NULL); ++ selmon->sel->wasfloating = 0; ++ } ++ resize(selmon->sel, x, y, w, h, 1); ++ selmon->sel->ismax = 1; ++ } ++ else { ++ resize(selmon->sel, selmon->sel->oldx, selmon->sel->oldy, selmon->sel->oldw, selmon->sel->oldh, 1); ++ if(!selmon->sel->wasfloating) ++ togglefloating(NULL); ++ selmon->sel->ismax = 0; ++ } ++ drawbar(selmon); ++ while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); ++} ++ ++void ++togglemaximize(const Arg *arg) { ++ maximize(selmon->wx, selmon->wy, selmon->ww - 2 * borderpx, selmon->wh - 2 * borderpx); ++} ++ ++void ++toggleverticalmax(const Arg *arg) { ++ maximize(selmon->sel->x, selmon->wy, selmon->sel->w, selmon->wh - 2 * borderpx); ++} ++ ++void ++togglehorizontalmax(const Arg *arg) { ++ maximize(selmon->wx, selmon->sel->y, selmon->ww - 2 * borderpx, selmon->sel->h); ++} diff --git a/dwm.suckless.org/patches/dwm-35db6d8-fancybar.diff b/dwm.suckless.org/patches/dwm-35db6d8-fancybar.diff @@ -1,69 +0,0 @@ -diff --git a/dwm.c b/dwm.c -index f896170..3da4cf2 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -692,11 +692,13 @@ dirtomon(int dir) { - - void - drawbar(Monitor *m) { -- int x, xx, w; -- unsigned int i, occ = 0, urg = 0; -+ int x, xx, w, tw, mw; -+ unsigned int i, occ = 0, urg = 0, n = 0, extra = 0; - Client *c; - - for(c = m->clients; c; c = c->next) { -+ if(ISVISIBLE(c)) -+ n++; - occ |= c->tags; - if(c->isurgent) - urg |= c->tags; -@@ -728,15 +730,40 @@ drawbar(Monitor *m) { - x = m->ww; - if((w = x - xx) > bh) { - x = xx; -- if(m->sel) { -- drw_setscheme(drw, m == selmon ? &scheme[SchemeSel] : &scheme[SchemeNorm]); -- drw_text(drw, x, 0, w, bh, m->sel->name, 0); -- drw_rect(drw, x, 0, w, bh, m->sel->isfixed, m->sel->isfloating, 0); -- } -- else { -- drw_setscheme(drw, &scheme[SchemeNorm]); -- drw_text(drw, x, 0, w, bh, NULL, 0); -+ if(n > 0) { -+ tw = m->sel->name ? TEXTW(m->sel->name) : 0; -+ mw = (tw >= w || n == 1) ? 0 : (w - tw) / (n - 1); -+ -+ i = 0; -+ for(c = m->clients; c; c = c->next) { -+ if(!ISVISIBLE(c) || c == m->sel) -+ continue; -+ tw = TEXTW(c->name); -+ if(tw < mw) -+ extra += (mw - tw); -+ else -+ i++; -+ } -+ if(i > 0) -+ mw += extra / i; -+ -+ for(c = m->clients; c; c = c->next) { -+ if(!ISVISIBLE(c)) -+ continue; -+ xx = x + w; -+ tw = TEXTW(c->name); -+ w = MIN(m->sel == c ? w : mw, tw); -+ -+ drw_setscheme(drw, m->sel == c ? &scheme[SchemeSel] : &scheme[SchemeNorm]); -+ drw_text(drw, x, 0, w, bh, c->name, 0); -+ drw_rect(drw, x, 0, w, bh, c->isfixed, c->isfloating, 0); -+ -+ x += w; -+ w = xx - x; -+ } - } -+ drw_setscheme(drw, &scheme[SchemeNorm]); -+ drw_text(drw, x, 0, w, bh, NULL, 0); - } - drw_map(drw, m->barwin, 0, 0, m->ww, bh); - } diff --git a/dwm.suckless.org/patches/dwm-6.0-xft.diff b/dwm.suckless.org/patches/dwm-6.0-xft.diff @@ -1,229 +0,0 @@ ---- ../dwm-o/dwm-6.0/dwm.c 2011-12-19 10:02:46.000000000 -0500 -+++ dwm.c 2012-05-16 22:33:00.043394484 -0400 -@@ -39,6 +39,7 @@ - #ifdef XINERAMA - #include <X11/extensions/Xinerama.h> - #endif /* XINERAMA */ -+#include <X11/Xft/Xft.h> - - /* macros */ - #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) -@@ -99,16 +100,15 @@ - - typedef struct { - int x, y, w, h; -- unsigned long norm[ColLast]; -- unsigned long sel[ColLast]; -+ XftColor norm[ColLast]; -+ XftColor sel[ColLast]; - Drawable drawable; - GC gc; - struct { - int ascent; - int descent; - int height; -- XFontSet set; -- XFontStruct *xfont; -+ XftFont *xfont; - } font; - } DC; /* draw context */ - -@@ -178,15 +178,15 @@ - static Monitor *dirtomon(int dir); - static void drawbar(Monitor *m); - static void drawbars(void); --static void drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]); --static void drawtext(const char *text, unsigned long col[ColLast], Bool invert); -+static void drawsquare(Bool filled, Bool empty, Bool invert, XftColor col[ColLast]); -+static void drawtext(const char *text, XftColor col[ColLast], Bool invert); - 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 unsigned long getcolor(const char *colstr); -+static XftColor getcolor(const char *colstr); - static Bool getrootptr(int *x, int *y); - static long getstate(Window w); - static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); -@@ -485,10 +485,6 @@ - for(m = mons; m; m = m->next) - while(m->stack) - unmanage(m->stack, False); -- if(dc.font.set) -- XFreeFontSet(dpy, dc.font.set); -- else -- XFreeFont(dpy, dc.font.xfont); - XUngrabKey(dpy, AnyKey, AnyModifier, root); - XFreePixmap(dpy, dc.drawable); - XFreeGC(dpy, dc.gc); -@@ -719,7 +715,7 @@ - drawbar(Monitor *m) { - int x; - unsigned int i, occ = 0, urg = 0; -- unsigned long *col; -+ XftColor *col; - Client *c; - - for(c = m->clients; c; c = c->next) { -@@ -774,10 +770,10 @@ - } - - void --drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { -+drawsquare(Bool filled, Bool empty, Bool invert, XftColor col[ColLast]) { - int x; - -- XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]); -+ XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG].pixel); - x = (dc.font.ascent + dc.font.descent + 2) / 4; - if(filled) - XFillRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x+1, x+1); -@@ -786,11 +782,12 @@ - } - - void --drawtext(const char *text, unsigned long col[ColLast], Bool invert) { -+drawtext(const char *text, XftColor col[ColLast], Bool invert) { - char buf[256]; - int i, x, y, h, len, olen; -+ XftDraw *d; - -- XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]); -+ XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG].pixel); - XFillRectangle(dpy, dc.drawable, dc.gc, dc.x, dc.y, dc.w, dc.h); - if(!text) - return; -@@ -805,11 +802,11 @@ - memcpy(buf, text, len); - if(len < olen) - for(i = len; i && i > len - 3; buf[--i] = '.'); -- XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]); -- if(dc.font.set) -- XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len); -- else -- XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); -+ -+ d = XftDrawCreate(dpy, dc.drawable, DefaultVisual(dpy, screen), DefaultColormap(dpy,screen)); -+ -+ XftDrawStringUtf8(d, &col[invert ? ColBG : ColFG], dc.font.xfont, x, y, (XftChar8 *) buf, len); -+ XftDrawDestroy(d); - } - - void -@@ -855,7 +852,7 @@ - detachstack(c); - attachstack(c); - grabbuttons(c, True); -- XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]); -+ XSetWindowBorder(dpy, c->win, dc.sel[ColBorder].pixel); - setfocus(c); - } - else -@@ -926,14 +923,14 @@ - return atom; - } - --unsigned long -+XftColor - getcolor(const char *colstr) { -- Colormap cmap = DefaultColormap(dpy, screen); -- XColor color; -+ XftColor color; - -- if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color)) -+ if(!XftColorAllocName(dpy, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen), colstr, &color)) - die("error, cannot allocate color '%s'\n", colstr); -- return color.pixel; -+ -+ return color; - } - - Bool -@@ -1034,35 +1031,13 @@ - - void - initfont(const char *fontstr) { -- char *def, **missing; -- int n; - -- dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); -- if(missing) { -- while(n--) -- fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]); -- XFreeStringList(missing); -- } -- if(dc.font.set) { -- XFontStruct **xfonts; -- char **font_names; -- -- dc.font.ascent = dc.font.descent = 0; -- XExtentsOfFontSet(dc.font.set); -- n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); -- while(n--) { -- dc.font.ascent = MAX(dc.font.ascent, (*xfonts)->ascent); -- dc.font.descent = MAX(dc.font.descent,(*xfonts)->descent); -- xfonts++; -- } -- } -- else { -- if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)) -- && !(dc.font.xfont = XLoadQueryFont(dpy, "fixed"))) -- die("error, cannot load font: '%s'\n", fontstr); -- dc.font.ascent = dc.font.xfont->ascent; -- dc.font.descent = dc.font.xfont->descent; -- } -+ if(!(dc.font.xfont = XftFontOpenName(dpy,screen,fontstr)) -+ && !(dc.font.xfont = XftFontOpenName(dpy,screen,"fixed"))) -+ die("error, cannot load font: '%s'\n", fontstr); -+ -+ dc.font.ascent = dc.font.xfont->ascent; -+ dc.font.descent = dc.font.xfont->descent; - dc.font.height = dc.font.ascent + dc.font.descent; - } - -@@ -1144,7 +1119,7 @@ - - wc.border_width = c->bw; - XConfigureWindow(dpy, w, CWBorderWidth, &wc); -- XSetWindowBorder(dpy, w, dc.norm[ColBorder]); -+ XSetWindowBorder(dpy, w, dc.norm[ColBorder].pixel); - configure(c); /* propagates border_width, if size doesn't change */ - updatewindowtype(c); - updatesizehints(c); -@@ -1621,8 +1596,6 @@ - dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), bh, DefaultDepth(dpy, screen)); - dc.gc = XCreateGC(dpy, root, 0, NULL); - XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); -- if(!dc.font.set) -- XSetFont(dpy, dc.gc, dc.font.xfont->fid); - /* init bars */ - updatebars(); - updatestatus(); -@@ -1692,13 +1665,9 @@ - - int - textnw(const char *text, unsigned int len) { -- XRectangle r; -- -- if(dc.font.set) { -- XmbTextExtents(dc.font.set, text, len, NULL, &r); -- return r.width; -- } -- return XTextWidth(dc.font.xfont, text, len); -+ XGlyphInfo ext; -+ XftTextExtentsUtf8(dpy, dc.font.xfont, (XftChar8 *) text, len, &ext); -+ return ext.xOff; - } - - void -@@ -1776,7 +1745,7 @@ - if(!c) - return; - grabbuttons(c, False); -- XSetWindowBorder(dpy, c->win, dc.norm[ColBorder]); -+ XSetWindowBorder(dpy, c->win, dc.norm[ColBorder].pixel); - if(setfocus) - XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); - } diff --git a/dwm.suckless.org/patches/dwm-6.1-attachabove.diff b/dwm.suckless.org/patches/dwm-6.1-attachabove.diff @@ -1,13 +1,11 @@ Author: Jan Christoph Ebersbach <jceb@e-jc.de> URL: http://dwm.suckless.org/patches/attachabove attachabove makes new clients attach above the selected client (instead of -always becoming the new master) – basically how Xmonad does it. +always becoming the new master) - basically how Xmonad does it. -Index: dwm/dwm.c -=================================================================== ---- dwm/dwm.c.orig 2014-02-09 15:24:20.560117200 +0100 -+++ dwm/dwm.c 2014-02-09 15:24:20.552117200 +0100 -@@ -146,6 +146,7 @@ +--- dwm/dwm.c.orig 2015-11-22 10:48:28.288368772 -0700 ++++ dwm/dwm.c 2015-11-22 10:51:45.308360761 -0700 +@@ -147,6 +147,7 @@ static int applysizehints(Client *c, int static void arrange(Monitor *m); static void arrangemon(Monitor *m); static void attach(Client *c); @@ -15,11 +13,12 @@ Index: dwm/dwm.c static void attachstack(Client *c); static void buttonpress(XEvent *e); static void checkotherwm(void); -@@ -401,6 +402,19 @@ +@@ -406,6 +407,20 @@ attach(Client *c) } void -+attachabove(Client *c) { ++attachabove(Client *c) ++{ + if(c->mon->sel == NULL || c->mon->sel == c->mon->clients || c->mon->sel->isfloating) { + attach(c); + return; @@ -32,19 +31,19 @@ Index: dwm/dwm.c +} + +void - attachstack(Client *c) { + attachstack(Client *c) + { c->snext = c->mon->stack; - c->mon->stack = c; -@@ -1051,7 +1065,7 @@ +@@ -1076,7 +1091,7 @@ manage(Window w, XWindowAttributes *wa) c->isfloating = c->oldstate = trans != None || c->isfixed; - if(c->isfloating) + if (c->isfloating) XRaiseWindow(dpy, c->win); - attach(c); + attachabove(c); attachstack(c); XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, (unsigned char *) &(c->win), 1); -@@ -1383,7 +1397,7 @@ +@@ -1434,7 +1449,7 @@ sendmon(Client *c, Monitor *m) detachstack(c); c->mon = m; c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ @@ -53,7 +52,7 @@ Index: dwm/dwm.c attachstack(c); focus(NULL); arrange(NULL); -@@ -1818,7 +1832,7 @@ +@@ -1891,7 +1906,7 @@ updategeom(void) m->clients = c->next; detachstack(c); c->mon = mons; @@ -61,4 +60,4 @@ Index: dwm/dwm.c + attachabove(c); attachstack(c); } - if(m == selmon) + if (m == selmon) diff --git a/dwm.suckless.org/patches/dwm-6.1-better-borders.diff b/dwm.suckless.org/patches/dwm-6.1-better-borders.diff @@ -4,89 +4,88 @@ window is visible. Additionally, any windows that are the same size as the monitor are considered full-screen and their borders removed accordingly. diff --git a/dwm.c b/dwm.c -index ffc8864..3ce8ebe 100644 +index 0362114..03fddb6 100644 --- a/dwm.c +++ b/dwm.c -@@ -308,6 +308,34 @@ applyrules(Client *c) { - c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; - } - -+void -+adjustborders(Monitor *m) { -+ Client *c, *l = NULL; -+ int visible = 0; -+ -+ for(c = m->clients; c; c = c->next) { -+ if (ISVISIBLE(c) && !c->isfloating && m->lt[m->sellt]->arrange) { -+ if (m->lt[m->sellt]->arrange == monocle) { -+ visible = 1; -+ c->oldbw = c->bw; -+ c->bw = 0; -+ } else { -+ visible++; -+ c->oldbw = c->bw; +@@ -393,9 +393,24 @@ arrange(Monitor *m) + void + arrangemon(Monitor *m) + { ++ int n = 0; ++ Client *c; + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); +- if (m->lt[m->sellt]->arrange) +- m->lt[m->sellt]->arrange(m); ++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); ++ if (n > 1 || !m->lt[m->sellt]->arrange) { ++ for (c = m->clients; c; c = c->next) { ++ if (ISVISIBLE(c) && (!m->lt[m->sellt]->arrange || !c->isfloating) && (c->bw != borderpx)) { ++ c->oldbw = c->oldbw; + c->bw = borderpx; ++ resizeclient(c, m->wx, m->wy, m->ww - (2 * c->bw), m->wh - (2 * c->bw)); + } -+ -+ l = c; + } ++ if (m->lt[m->sellt]->arrange) { ++ m->lt[m->sellt]->arrange(m); ++ } ++ } else { ++ monocle(m); + } -+ -+ if (l && visible == 1 && l->bw) { -+ l->oldbw = l->bw; -+ l->bw = 0; -+ resizeclient(l, l->x, l->y, l->w, l->h); -+ } -+} -+ - Bool - applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) { - Bool baseismin; -@@ -376,10 +404,13 @@ applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) { + } void - arrange(Monitor *m) { -- if(m) -+ if(m) { -+ adjustborders(m); - showhide(m->stack); -- else for(m = mons; m; m = m->next) -+ } else for(m = mons; m; m = m->next) { -+ adjustborders(m); - showhide(m->stack); -+ } - if(m) { - arrangemon(m); - restack(m); -@@ -1036,7 +1067,20 @@ manage(Window w, XWindowAttributes *wa) { - /* only fix client y-offset, if the client center might cover the bar */ - c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx) - && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); -- c->bw = borderpx; -+ -+ updatewindowtype(c); -+ if (c->isfloating) { -+ c->bw = c->isfullscreen ? 0 : borderpx; -+ } else { -+ c->bw = 0; -+ for(t = c->mon->clients; t; t = c->next) { -+ if (!t->isfloating && c != t && c->tags & t->tags) { -+ c->bw = borderpx; -+ break; -+ } +@@ -1117,16 +1132,25 @@ maprequest(XEvent *e) + void + monocle(Monitor *m) + { +- unsigned int n = 0; ++ unsigned int n = 0, r = 0; + Client *c; + + for (c = m->clients; c; c = c->next) + if (ISVISIBLE(c)) + n++; +- if (n > 0) /* override layout symbol */ ++ if (n > 0 && m->lt[m->sellt]->arrange == monocle) /* 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); ++ for(c = nexttiled(m->clients); c; c = nexttiled(c->next)) { ++ if (c->bw) { ++ c->oldbw = c->bw; ++ c->bw = 0; ++ r = 1; ++ } ++ resize(c, m->wx, m->wy, m->ww - (2 * c->bw), m->wh - (2 * c->bw), False); ++ if(r) { ++ resizeclient(c, m->wx, m->wy, m->ww - (2 * c->bw), m->wh - (2 * c->bw)); + } -+ adjustborders(c->mon); + } + } + + void +@@ -1706,9 +1730,11 @@ togglefloating(const Arg *arg) + if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ + return; + selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed; +- if (selmon->sel->isfloating) +- resize(selmon->sel, selmon->sel->x, selmon->sel->y, +- selmon->sel->w, selmon->sel->h, 0); ++ if (selmon->sel->isfloating) { ++ selmon->sel->oldbw = selmon->sel->bw; ++ selmon->sel->bw = borderpx; ++ resizeclient(selmon->sel, selmon->wx, selmon->wy, selmon->ww - (2 * selmon->sel->bw), selmon->wh - (2 * selmon->sel->bw)); ++ } + arrange(selmon); + } - wc.border_width = c->bw; - XConfigureWindow(dpy, w, CWBorderWidth, &wc); -@@ -1933,7 +1977,8 @@ updatewindowtype(Client *c) { +@@ -2003,7 +2029,8 @@ updatewindowtype(Client *c) Atom state = getatomprop(c, netatom[NetWMState]); Atom wtype = getatomprop(c, netatom[NetWMWindowType]); -- if(state == netatom[NetWMFullscreen]) +- if (state == netatom[NetWMFullscreen]) + if(state == netatom[NetWMFullscreen] || -+ (WIDTH(c) == (c->mon->mx + c->mon->mw) && (HEIGHT(c) == (c->mon->my + c->mon->mh)))) - setfullscreen(c, True); - if(wtype == netatom[NetWMWindowTypeDialog]) - c->isfloating = True; ++ (WIDTH(c) >= (c->mon->mx + c->mon->mw) && (HEIGHT(c) >= (c->mon->my + c->mon->mh)))) + setfullscreen(c, 1); + if (wtype == netatom[NetWMWindowTypeDialog]) + c->isfloating = 1; diff --git a/dwm.suckless.org/patches/dwm-6.1-center.diff b/dwm.suckless.org/patches/dwm-6.1-center.diff @@ -0,0 +1,58 @@ +diff --git a/config.def.h b/config.def.h +index 7054c06..e0cdcf3 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -24,9 +24,9 @@ static const Rule rules[] = { + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ +- /* class instance title tags mask isfloating monitor */ +- { "Gimp", NULL, NULL, 0, 1, -1 }, +- { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, ++ /* class instance title tags mask iscentered isfloating monitor */ ++ { "Gimp", NULL, NULL, 0, 0, 1, -1 }, ++ { "Firefox", NULL, NULL, 1 << 8, 0, 0, -1 }, + }; + + /* layout(s) */ +diff --git a/dwm.c b/dwm.c +index 0362114..4aaaa60 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -92,7 +92,7 @@ struct Client { + int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int bw, oldbw; + unsigned int tags; +- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; ++ int isfixed, iscentered, isfloating, isurgent, neverfocus, oldstate, isfullscreen; + Client *next; + Client *snext; + Monitor *mon; +@@ -137,6 +137,7 @@ typedef struct { + const char *instance; + const char *title; + unsigned int tags; ++ int iscentered; + int isfloating; + int monitor; + } Rule; +@@ -296,6 +297,7 @@ applyrules(Client *c) + && (!r->class || strstr(class, r->class)) + && (!r->instance || strstr(instance, r->instance))) + { ++ c->iscentered = r->iscentered; + c->isfloating = r->isfloating; + c->tags |= r->tags; + for (m = mons; m && m->num != r->monitor; m = m->next); +@@ -1063,6 +1065,11 @@ manage(Window w, XWindowAttributes *wa) + && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); + c->bw = borderpx; + ++ if(c->iscentered) { ++ c->x = (c->mon->mw - WIDTH(c)) / 2; ++ c->y = (c->mon->mh - HEIGHT(c)) / 2; ++ } ++ + wc.border_width = c->bw; + XConfigureWindow(dpy, w, CWBorderWidth, &wc); + XSetWindowBorder(dpy, w, scheme[SchemeNorm].border->pix); diff --git a/dwm.suckless.org/patches/dwm-6.1-centeredmaster.diff b/dwm.suckless.org/patches/dwm-6.1-centeredmaster.diff @@ -1,58 +1,59 @@ diff --git a/dwm.c b/dwm.c -index 783fcdb..ab179d8 100644 +index 0362114..fa5ae4c 100644 --- a/dwm.c +++ b/dwm.c -@@ -215,6 +215,7 @@ static void tag(const Arg *arg); +@@ -209,6 +209,7 @@ static void spawn(const Arg *arg); + static void tag(const Arg *arg); static void tagmon(const Arg *arg); static void tile(Monitor *); - static void htile(Monitor *); +static void centeredmaster(Monitor *); static void togglebar(const Arg *arg); static void togglefloating(const Arg *arg); static void toggletag(const Arg *arg); -@@ -1748,6 +1749,45 @@ htile(Monitor *m) { +@@ -1690,6 +1691,46 @@ tile(Monitor *m) } void -+centeredmaster(Monitor *m) { ++centeredmaster(Monitor *m) ++{ + unsigned int i, n, w, mh, mw, mx, mxo, my, myo, tx; + Client *c; + -+ // Count number of clients in the selected monitor ++ // Count number of clients in the selected monitor + for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if(n == 0) + return; + -+ // initialize nmaster area ++ // initialize nmaster area + if(n > m->nmaster) { -+ // go mfact box in the center if more than nmaster clients ++ // go mfact box in the center if more than nmaster clients + mw = m->nmaster ? m->ww * m->mfact : 0; + mh = m->nmaster ? m->wh * m->mfact : 0; -+ mx = mxo = (m->ww - mw) / 2; -+ my = myo = (m->wh - mh) / 2; -+ } else { -+ // Go fullscreen if all clients are in the master area ++ mx = mxo = (m->ww - mw) / 2; ++ my = myo = (m->wh - mh) / 2; ++ } else { ++ // Go fullscreen if all clients are in the master area + mh = m->wh; -+ mw = m->ww; -+ mx = mxo = 0; -+ my = mxo = 0; -+ } ++ mw = m->ww; ++ mx = mxo = 0; ++ my = mxo = 0; ++ } + + for(i = tx = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if(i < m->nmaster) { -+ // nmaster clients are stacked horizontally, in the center of the screen -+ w = (mw + mxo - mx) / (MIN(n, m->nmaster) - i); ++ // nmaster clients are stacked horizontally, in the center of the screen ++ w = (mw + mxo - mx) / (MIN(n, m->nmaster) - i); + resize(c, m->wx + mx, m->wy + my, w - (2*c->bw), mh - (2*c->bw), False); + mx += WIDTH(c); + } else { -+ // Stack clients are stacked horizontally -+ w = (m->ww - tx) / (n - i); -+ resize(c, tx, m->wy, w - (2*c->bw), m->wh - (2*c->bw), False); ++ // Stack clients are stacked horizontally ++ w = (m->ww - tx) / (n - i); ++ resize(c, m->wx + tx, m->wy, w - (2*c->bw), m->wh - (2*c->bw), False); + tx += WIDTH(c); + } +} + +void - togglebar(const Arg *arg) { - selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; - updatebarpos(selmon); + togglebar(const Arg *arg) + { + selmon->showbar = !selmon->showbar; diff --git a/dwm.suckless.org/patches/dwm-6.1-combo.diff b/dwm.suckless.org/patches/dwm-6.1-combo.diff @@ -0,0 +1,75 @@ +diff --git a/dwm.c b/dwm.c +index 0362114..40b7a99 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -234,6 +234,11 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee); + static int xerrorstart(Display *dpy, XErrorEvent *ee); + static void zoom(const Arg *arg); + ++static void keyrelease(XEvent *e); ++static void combotag(const Arg *arg); ++static void comboview(const Arg *arg); ++ ++ + /* variables */ + static const char broken[] = "broken"; + static char stext[256]; +@@ -244,6 +249,7 @@ static int (*xerrorxlib)(Display *, XErrorEvent *); + static unsigned int numlockmask = 0; + static void (*handler[LASTEvent]) (XEvent *) = { + [ButtonPress] = buttonpress, ++ [ButtonRelease] = keyrelease, + [ClientMessage] = clientmessage, + [ConfigureRequest] = configurerequest, + [ConfigureNotify] = configurenotify, +@@ -251,6 +257,7 @@ static void (*handler[LASTEvent]) (XEvent *) = { + [EnterNotify] = enternotify, + [Expose] = expose, + [FocusIn] = focusin, ++ [KeyRelease] = keyrelease, + [KeyPress] = keypress, + [MappingNotify] = mappingnotify, + [MapRequest] = maprequest, +@@ -274,6 +281,42 @@ static Window root; + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + + /* function implementations */ ++static int combo = 0; ++ ++void ++keyrelease(XEvent *e) { ++ combo = 0; ++} ++ ++void ++combotag(const Arg *arg) { ++ if(selmon->sel && arg->ui & TAGMASK) { ++ if (combo) { ++ selmon->sel->tags |= arg->ui & TAGMASK; ++ } else { ++ combo = 1; ++ selmon->sel->tags = arg->ui & TAGMASK; ++ } ++ focus(NULL); ++ arrange(selmon); ++ } ++} ++ ++void ++comboview(const Arg *arg) { ++ unsigned newtags = arg->ui & TAGMASK; ++ if (combo) { ++ selmon->tagset[selmon->seltags] |= newtags; ++ } else { ++ selmon->seltags ^= 1; /*toggle tagset*/ ++ combo = 1; ++ if (newtags) ++ selmon->tagset[selmon->seltags] = newtags; ++ } ++ focus(NULL); ++ arrange(selmon); ++} ++ + void + applyrules(Client *c) + { diff --git a/dwm.suckless.org/patches/dwm-6.1-dualstatus.diff b/dwm.suckless.org/patches/dwm-6.1-dualstatus.diff @@ -1,16 +1,16 @@ diff --git a/config.def.h b/config.def.h -index eaae8f3..05ca3cb 100644 +index 7054c06..b96107a 100644 --- a/config.def.h +++ b/config.def.h -@@ -17,6 +17,7 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ +@@ -15,6 +15,7 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ static const unsigned int snap = 32; /* snap pixel */ - static const Bool showbar = True; /* False means no bar */ - static const Bool topbar = True; /* False means bottom bar */ -+static const Bool extrabar = True; /* False means no extra bar */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ ++static const int extrabar = 1; /* 0 means no extra bar */ /* tagging */ static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; -@@ -64,6 +65,7 @@ static Key keys[] = { +@@ -62,6 +63,7 @@ static Key keys[] = { { MODKEY, XK_p, spawn, {.v = dmenucmd } }, { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, { MODKEY, XK_b, togglebar, {0} }, @@ -19,7 +19,7 @@ index eaae8f3..05ca3cb 100644 { MODKEY, XK_k, focusstack, {.i = -1 } }, { MODKEY, XK_i, incnmaster, {.i = +1 } }, diff --git a/dwm.c b/dwm.c -index 169adcb..0eae8b2 100644 +index 0362114..9b7cd74 100644 --- a/dwm.c +++ b/dwm.c @@ -141,6 +141,13 @@ typedef struct { @@ -28,14 +28,14 @@ index 169adcb..0eae8b2 100644 +typedef struct { + int y; -+ Bool show; ++ int show; + Window win; + char text[256]; +} Bar; + /* function declarations */ static void applyrules(Client *c); - static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact); + static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); @@ -210,6 +217,7 @@ static void tag(const Arg *arg); static void tagmon(const Arg *arg); static void tile(Monitor *); @@ -52,24 +52,24 @@ index 169adcb..0eae8b2 100644 /* configuration, allows nested code to access above variables */ #include "config.h" -@@ -469,6 +478,8 @@ cleanup(void) { - while(m->stack) - unmanage(m->stack, False); +@@ -477,6 +486,8 @@ cleanup(void) + while (m->stack) + unmanage(m->stack, 0); XUngrabKey(dpy, AnyKey, AnyModifier, root); + XUnmapWindow(dpy, eb.win); + XDestroyWindow(dpy, eb.win); - while(mons) + while (mons) cleanupmon(mons); - drw_cur_free(drw, cursor[CurNormal]); -@@ -568,6 +579,7 @@ configurenotify(XEvent *e) { + for (i = 0; i < CurLast; i++) +@@ -578,6 +589,7 @@ configurenotify(XEvent *e) updatebars(); - for(m = mons; m; m = m->next) + for (m = mons; m; m = m->next) XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); + XMoveResizeWindow(dpy, eb.win, mons->wx, eb.y, mons->ww, bh); focus(NULL); arrange(NULL); } -@@ -738,6 +750,9 @@ drawbar(Monitor *m) { +@@ -751,6 +763,9 @@ drawbar(Monitor *m) } } drw_map(drw, m->barwin, 0, 0, m->ww, bh); @@ -79,19 +79,20 @@ index 169adcb..0eae8b2 100644 } void -@@ -1509,6 +1524,7 @@ setup(void) { +@@ -1558,6 +1573,7 @@ setup(void) root = RootWindow(dpy, screen); drw = drw_create(dpy, screen, root, sw, sh); drw_load_fonts(drw, fonts, LENGTH(fonts)); + eb.show = extrabar; if (!drw->fontcount) - die("No fonts could be loaded.\n"); + die("no fonts could be loaded.\n"); bh = drw->fonts[0]->h + 2; -@@ -1643,6 +1659,16 @@ togglebar(const Arg *arg) { +@@ -1699,6 +1715,17 @@ togglebar(const Arg *arg) } void -+toggleextrabar(const Arg *arg) { ++toggleextrabar(const Arg *arg) ++{ + if(selmon == mons) { + eb.show = !eb.show; + updatebarpos(selmon); @@ -101,26 +102,26 @@ index 169adcb..0eae8b2 100644 +} + +void - togglefloating(const Arg *arg) { - if(!selmon->sel) - return; -@@ -1747,6 +1773,13 @@ updatebars(void) { + togglefloating(const Arg *arg) + { + if (!selmon->sel) +@@ -1810,6 +1837,13 @@ updatebars(void) XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); XMapRaised(dpy, m->barwin); } + if(!eb.win) { + eb.win = XCreateWindow(dpy, root, mons->wx, eb.y, mons->ww, bh, 0, DefaultDepth(dpy, screen), -+ CopyFromParent, DefaultVisual(dpy, screen), -+ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); ++ CopyFromParent, DefaultVisual(dpy, screen), ++ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, eb.win, cursor[CurNormal]->cursor); + XMapRaised(dpy, eb.win); + } } void -@@ -1760,6 +1793,13 @@ updatebarpos(Monitor *m) { - } - else +@@ -1823,6 +1857,13 @@ updatebarpos(Monitor *m) + m->wy = m->topbar ? m->wy + bh : m->wy; + } else m->by = -bh; + if(m == mons && eb.show) { + m->wh -= bh; @@ -132,11 +133,11 @@ index 169adcb..0eae8b2 100644 } void -@@ -1932,8 +1972,21 @@ updatetitle(Client *c) { - +@@ -1992,8 +2033,21 @@ updatetitle(Client *c) void - updatestatus(void) { -- if(!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) + updatestatus(void) + { +- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) + char text[512]; + if(!gettextprop(root, XA_WM_NAME, text, sizeof(text))) { strcpy(stext, "dwm-"VERSION); diff --git a/dwm.suckless.org/patches/dwm-6.1-fancybar.diff b/dwm.suckless.org/patches/dwm-6.1-fancybar.diff @@ -0,0 +1,70 @@ +diff --git a/dwm.c b/dwm.c +index 0362114..b74e787 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -704,13 +704,15 @@ dirtomon(int dir) + void + drawbar(Monitor *m) + { +- int x, xx, w, dx; +- unsigned int i, occ = 0, urg = 0; ++ int x, xx, w, dx, tw, mw; ++ unsigned int i, occ = 0, urg = 0, n = 0, extra = 0; + Client *c; + + dx = (drw->fonts[0]->ascent + drw->fonts[0]->descent + 2) / 4; + + for (c = m->clients; c; c = c->next) { ++ if (ISVISIBLE(c)) ++ n++; + occ |= c->tags; + if (c->isurgent) + urg |= c->tags; +@@ -741,14 +743,40 @@ drawbar(Monitor *m) + x = m->ww; + if ((w = x - xx) > bh) { + x = xx; +- if (m->sel) { +- drw_setscheme(drw, m == selmon ? &scheme[SchemeSel] : &scheme[SchemeNorm]); +- drw_text(drw, x, 0, w, bh, m->sel->name, 0); +- drw_rect(drw, x + 1, 1, dx, dx, m->sel->isfixed, m->sel->isfloating, 0); +- } else { +- drw_setscheme(drw, &scheme[SchemeNorm]); +- drw_rect(drw, x, 0, w, bh, 1, 0, 1); ++ if (n > 0) { ++ tw = m->sel->name ? TEXTW(m->sel->name) : 0; ++ mw = (tw >= w || n == 1) ? 0 : (w - tw) / (n - 1); ++ ++ i = 0; ++ for (c = m->clients; c; c = c->next) { ++ if (!ISVISIBLE(c) || c == m->sel) ++ continue; ++ tw = TEXTW(c->name); ++ if(tw < mw) ++ extra += (mw - tw); ++ else ++ i++; ++ } ++ if (i > 0) ++ mw += extra / i; ++ ++ for (c = m->clients; c; c = c->next) { ++ if (!ISVISIBLE(c)) ++ continue; ++ xx = x + w; ++ tw = TEXTW(c->name); ++ w = MIN(m->sel == c ? w : mw, tw); ++ ++ drw_setscheme(drw, m->sel == c ? &scheme[SchemeSel] : &scheme[SchemeNorm]); ++ drw_text(drw, x, 0, w, bh, c->name, 0); ++ drw_rect(drw, x + 1, 1, dx, dx, c->isfixed, c->isfloating, 0); ++ ++ x += w; ++ w = xx - x; ++ } + } ++ drw_setscheme(drw, &scheme[SchemeNorm]); ++ drw_rect(drw, x, 0, w, bh, 1, 0, 1); + } + drw_map(drw, m->barwin, 0, 0, m->ww, bh); + } diff --git a/dwm.suckless.org/patches/dwm-6.1-fancybarclickable.diff b/dwm.suckless.org/patches/dwm-6.1-fancybarclickable.diff @@ -6,7 +6,7 @@ index 875885b..05865bb 100644 /* click event mask button function argument */ { ClkLtSymbol, 0, Button1, setlayout, {0} }, { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, -+ { ClkWinTitle, 0, Button1, focusonclick, {0} }, ++ { ClkWinTitle, 0, Button1, focusonclick, {0} }, { ClkWinTitle, 0, Button2, zoom, {0} }, { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, { ClkClientWin, MODKEY, Button1, movemouse, {0} }, @@ -18,8 +18,8 @@ index f896170..cc2a4f2 100644 Monitor *next; Window barwin; const Layout *lt[2]; -+ int titlebarbegin; -+ int titlebarend; ++ int titlebarbegin; ++ int titlebarend; }; typedef struct { @@ -44,9 +44,9 @@ index f896170..cc2a4f2 100644 click = ClkStatusText; - else + else { -+ arg.ui = ev->x; ++ arg.ui = ev->x; click = ClkWinTitle; -+ } ++ } } else if((c = wintoclient(ev->window))) { focus(c); @@ -67,13 +67,13 @@ index f896170..cc2a4f2 100644 - unsigned int i, occ = 0, urg = 0; - Client *c; + int x, xx, w, ow, mw = 0, extra, tw, a = 0, s = 0; -+ char posbuf[10]; ++ char posbuf[10]; + unsigned int i, occ = 0, urg = 0, n = 0; + Client *c, *firstvis, *lastvis = NULL; for(c = m->clients; c; c = c->next) { -+ if(ISVISIBLE(c)) -+ n++; ++ if(ISVISIBLE(c)) ++ n++; occ |= c->tags; if(c->isurgent) urg |= c->tags; @@ -82,36 +82,35 @@ index f896170..cc2a4f2 100644 xx = x; if(m == selmon) { /* status is only drawn on selected monitor */ - w = TEXTW(stext); -+ if(m->lt[m->sellt]->arrange == monocle){ -+ x = xx; -+ for(c = nexttiled(m->clients), a = 0, s = 0; c; c = nexttiled(c->next), a++) { -+ if(c == m->stack) -+ s = a; -+ } -+ if(!s && a) -+ s = a; -+ snprintf(posbuf, LENGTH(posbuf), "[%d/%d]", s, a); -+ w = TEXTW(posbuf); -+ drw_text(drw, x, 0, w, bh, posbuf, 0); -+ xx = x + w; -+ } ++ if(m->lt[m->sellt]->arrange == monocle){ ++ x = xx; ++ for(c = nexttiled(m->clients), a = 0, s = 0; c; c = nexttiled(c->next), a++) { ++ if(c == m->stack) ++ s = a; ++ } ++ if(!s && a) ++ s = a; ++ snprintf(posbuf, LENGTH(posbuf), "[%d/%d]", s, a); ++ w = TEXTW(posbuf); ++ drw_text(drw, x, 0, w, bh, posbuf, 0); ++ xx = x + w; ++ } + -+ /* -+ char *buf = stext, *ptr = buf; -+ while (*ptr) { -+ for (i = 0; *ptr < 0; i++, ptr++); -+ w 2+= drw_font_getexts_width(drw->font, buf, i); -+ w += TEXTW(buf); -+ buf=++ptr; -+ }*/ -+ w = TEXTW(stext); ++ /* char *buf = stext, *ptr = buf; ++ while (*ptr) { ++ for (i = 0; *ptr < 0; i++, ptr++); ++ w 2+= drw_font_getexts_width(drw->font, buf, i); ++ w += TEXTW(buf); ++ buf=++ptr; ++ } */ ++ w = TEXTW(stext); + x = m->ww - w; if(x < xx) { x = xx; w = m->ww - xx; } -+ m->titlebarend=x; ++ m->titlebarend=x; drw_text(drw, x, 0, w, bh, stext, 0); } - else @@ -125,72 +124,72 @@ index f896170..cc2a4f2 100644 - drw_rect(drw, x, 0, w, bh, m->sel->isfixed, m->sel->isfloating, 0); - } - else { -+ m->titlebarbegin=x; -+ } -+ for(c = m->clients; c && !ISVISIBLE(c); c = c->next); -+ firstvis = c; ++ m->titlebarbegin=x; ++ } ++ for(c = m->clients; c && !ISVISIBLE(c); c = c->next); ++ firstvis = c; + -+ drw_setscheme(drw, m == selmon ? &scheme[SchemeSel] : &scheme[SchemeNorm]); -+ w = x - xx; -+ x = xx; ++ drw_setscheme(drw, m == selmon ? &scheme[SchemeSel] : &scheme[SchemeNorm]); ++ w = x - xx; ++ x = xx; + -+ if(n > 0) { -+ mw = w / n; -+ extra = 0; -+ i = 0; ++ if(n > 0) { ++ mw = w / n; ++ extra = 0; ++ i = 0; + -+ while(c) { -+ lastvis = c; -+ tw = TEXTW(c->name); -+ if(tw < mw) extra += (mw - tw); else i++; -+ for(c = c->next; c && !ISVISIBLE(c); c = c->next); -+ } ++ while(c) { ++ lastvis = c; ++ tw = TEXTW(c->name); ++ if(tw < mw) extra += (mw - tw); else i++; ++ for(c = c->next; c && !ISVISIBLE(c); c = c->next); ++ } + -+ if(i > 0) mw += extra / i; ++ if(i > 0) mw += extra / i; + -+ c = firstvis; -+ xx = x; -+ } -+ m->titlebarbegin=x; -+ while(w > bh) { -+ if(c) { -+ ow = w; -+ tw = TEXTW(c->name); -+ w = MIN(ow, tw); ++ c = firstvis; ++ xx = x; ++ } ++ m->titlebarbegin=x; ++ while(w > bh) { ++ if(c) { ++ ow = w; ++ tw = TEXTW(c->name); ++ w = MIN(ow, tw); + -+ if(w > mw) w = mw; -+ if(c == lastvis) w = ow; ++ if(w > mw) w = mw; ++ if(c == lastvis) w = ow; + -+ drw_text(drw, x, 0, w, bh, c->name, False); -+ if(c != firstvis) drawline(x, 0); -+ drw_rect(drw, x, 0, w, bh, m->sel->isfixed, m->sel->isfloating, True); ++ drw_text(drw, x, 0, w, bh, c->name, False); ++ if(c != firstvis) drawline(x, 0); ++ drw_rect(drw, x, 0, w, bh, m->sel->isfixed, m->sel->isfloating, True); + -+ x += w; -+ w = ow - w; -+ for(c = c->next; c && !ISVISIBLE(c); c = c->next); ++ x += w; ++ w = ow - w; ++ for(c = c->next; c && !ISVISIBLE(c); c = c->next); + } else { drw_setscheme(drw, &scheme[SchemeNorm]); drw_text(drw, x, 0, w, bh, NULL, 0); -+ break; ++ break; } } + -+ if(m == selmon && m->sel && ISVISIBLE(m->sel)) { -+ drw_text(drw, x, 0, w, bh, m->sel->name, True); -+ drw_rect(drw, x, 0, w, bh, m->sel->isfixed, m->sel->isfloating, True); -+ } ++ if(m == selmon && m->sel && ISVISIBLE(m->sel)) { ++ drw_text(drw, x, 0, w, bh, m->sel->name, True); ++ drw_rect(drw, x, 0, w, bh, m->sel->isfixed, m->sel->isfloating, True); ++ } + drw_map(drw, m->barwin, 0, 0, m->ww, bh); } void +drawline(int x, int y) { -+ XGCValues gcv; ++ XGCValues gcv; + -+ gcv.foreground = drw->scheme->fg->rgb; ++ gcv.foreground = drw->scheme->fg->rgb; + -+ XChangeGC(dpy, drw->gc, GCForeground, &gcv); -+ XDrawLine(dpy, drw->drawable, drw->gc, x, y, x, y + (drw->font->ascent + drw->font->descent + 2)); ++ XChangeGC(dpy, drw->gc, GCForeground, &gcv); ++ XDrawLine(dpy, drw->drawable, drw->gc, x, y, x, y + (drw->font->ascent + drw->font->descent + 2)); +} + +void @@ -202,47 +201,47 @@ index f896170..cc2a4f2 100644 void +focusonclick(const Arg *arg) { -+ int x, w, mw = 0, tw, n = 0, i = 0, extra = 0; -+ Monitor *m = selmon; -+ Client *c, *firstvis; ++ int x, w, mw = 0, tw, n = 0, i = 0, extra = 0; ++ Monitor *m = selmon; ++ Client *c, *firstvis; + -+ for(c = m->clients; c && !ISVISIBLE(c); c = c->next); -+ firstvis = c; ++ for(c = m->clients; c && !ISVISIBLE(c); c = c->next); ++ firstvis = c; + -+ for(c = m->clients; c; c = c->next) -+ if (ISVISIBLE(c)) -+ n++; ++ for(c = m->clients; c; c = c->next) ++ if (ISVISIBLE(c)) ++ n++; + -+ if(n > 0) { -+ mw = (m->titlebarend - m->titlebarbegin) / n; -+ c = firstvis; -+ while(c) { -+ tw = TEXTW(c->name); -+ if(tw < mw) extra += (mw - tw); else i++; -+ for(c = c->next; c && !ISVISIBLE(c); c = c->next); -+ } -+ if(i > 0) mw += extra / i; -+ } ++ if(n > 0) { ++ mw = (m->titlebarend - m->titlebarbegin) / n; ++ c = firstvis; ++ while(c) { ++ tw = TEXTW(c->name); ++ if(tw < mw) extra += (mw - tw); else i++; ++ for(c = c->next; c && !ISVISIBLE(c); c = c->next); ++ } ++ if(i > 0) mw += extra / i; ++ } + -+ x=m->titlebarbegin; ++ x=m->titlebarbegin; + -+ c = firstvis; -+ while(x < m->titlebarend) { -+ if(c) { -+ w=MIN(TEXTW(c->name), mw); -+ if (x < arg->i && x+w > arg->i) { -+ focus(c); -+ restack(selmon); -+ break; -+ } else { -+ x+=w; -+ } ++ c = firstvis; ++ while(x < m->titlebarend) { ++ if(c) { ++ w=MIN(TEXTW(c->name), mw); ++ if (x < arg->i && x+w > arg->i) { ++ focus(c); ++ restack(selmon); ++ break; ++ } else { ++ x+=w; ++ } + -+ for(c = c->next; c && !ISVISIBLE(c); c = c->next); -+ } else { -+ break; -+ } -+ } ++ for(c = c->next; c && !ISVISIBLE(c); c = c->next); ++ } else { ++ break; ++ } ++ } +} + +void @@ -255,7 +254,7 @@ index f896170..cc2a4f2 100644 updatetitle(c); - if(c == c->mon->sel) - drawbar(c->mon); -+ drawbar(c->mon); ++ drawbar(c->mon); } if(ev->atom == netatom[NetWMWindowType]) updatewindowtype(c); diff --git a/dwm.suckless.org/patches/dwm-6.1-hide_vacant_tags.diff b/dwm.suckless.org/patches/dwm-6.1-hide_vacant_tags.diff @@ -1,10 +1,10 @@ diff --git a/dwm.c b/dwm.c -index ffc8864..0e5d3f1 100644 +index 0362114..0da6e27 100644 --- a/dwm.c +++ b/dwm.c -@@ -423,9 +423,15 @@ buttonpress(XEvent *e) { +@@ -430,9 +430,15 @@ buttonpress(XEvent *e) } - if(ev->window == selmon->barwin) { + if (ev->window == selmon->barwin) { i = x = 0; - do + unsigned int occ = 0; @@ -15,22 +15,22 @@ index ffc8864..0e5d3f1 100644 + if(!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) + continue; x += TEXTW(tags[i]); -- while(ev->x >= x && ++i < LENGTH(tags)); -+ } while(ev->x >= x && ++i < LENGTH(tags)); - if(i < LENGTH(tags)) { +- while (ev->x >= x && ++i < LENGTH(tags)); ++ } while (ev->x >= x && ++i < LENGTH(tags)); + if (i < LENGTH(tags)) { click = ClkTagBar; arg.ui = 1 << i; -@@ -703,11 +709,14 @@ drawbar(Monitor *m) { +@@ -717,11 +723,14 @@ drawbar(Monitor *m) } x = 0; - for(i = 0; i < LENGTH(tags); i++) { + for (i = 0; i < LENGTH(tags); i++) { + /* do not draw vacant tags */ + if(!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) + continue; w = TEXTW(tags[i]); drw_setscheme(drw, m->tagset[m->seltags] & 1 << i ? &scheme[SchemeSel] : &scheme[SchemeNorm]); drw_text(drw, x, 0, w, bh, tags[i], urg & 1 << i); - drw_rect(drw, x, 0, w, bh, m == selmon && selmon->sel && selmon->sel->tags & 1 << i, + drw_rect(drw, x + 1, 1, dx, dx, m == selmon && selmon->sel && selmon->sel->tags & 1 << i, - occ & 1 << i, urg & 1 << i); + 0, urg & 1 << i); x += w; diff --git a/dwm.suckless.org/patches/dwm-6.1-horizgrid.diff b/dwm.suckless.org/patches/dwm-6.1-horizgrid.diff @@ -0,0 +1,70 @@ +From 064e1d48631cd9b03f32b42d7be79677197ee42f Mon Sep 17 00:00:00 2001 +From: Marshall Mason <marshallmason3@gmail.com> +Date: Mon, 9 Nov 2015 12:38:28 -0800 +Subject: [PATCH] Added horizgrid function + +--- + config.def.h | 2 ++ + horizgrid.c | 32 ++++++++++++++++++++++++++++++++ + 2 files changed, 34 insertions(+) + create mode 100644 horizgrid.c + +diff --git a/config.def.h b/config.def.h +index eaae8f3..c2ad519 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -36,11 +36,13 @@ static const float mfact = 0.55; /* factor of master area size [0.05..0.95] + static const int nmaster = 1; /* number of clients in master area */ + static const Bool resizehints = True; /* True means respect size hints in tiled resizals */ + ++#include "horizgrid.c" + static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, ++ { "###", horizgrid }, + }; + + /* key definitions */ +diff --git a/horizgrid.c b/horizgrid.c +new file mode 100644 +index 0000000..51ce0f8 +--- /dev/null ++++ b/horizgrid.c +@@ -0,0 +1,32 @@ ++void ++horizgrid(Monitor *m) { ++ Client *c; ++ unsigned int n, i; ++ int w = 0; ++ int ntop, nbottom = 0; ++ ++ /* Count windows */ ++ for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); ++ ++ if(n == 0) ++ return; ++ else if(n == 1) { /* Just fill the whole screen */ ++ c = nexttiled(m->clients); ++ resize(c, m->wx, m->wy, m->ww - (2*c->bw), m->wh - (2*c->bw), False); ++ } else if(n == 2) { /* Split vertically */ ++ w = m->ww / 2; ++ c = nexttiled(m->clients); ++ resize(c, m->wx, m->wy, w - (2*c->bw), m->wh - (2*c->bw), False); ++ c = nexttiled(c->next); ++ resize(c, m->wx + w, m->wy, w - (2*c->bw), m->wh - (2*c->bw), False); ++ } else { ++ ntop = n / 2; ++ nbottom = n - ntop; ++ for(i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { ++ if(i < ntop) ++ resize(c, m->wx + i * m->ww / ntop, m->wy, m->ww / ntop - (2*c->bw), m->wh / 2 - (2*c->bw), False); ++ else ++ resize(c, m->wx + (i - ntop) * m->ww / nbottom, m->wy + m->wh / 2, m->ww / nbottom - (2*c->bw), m->wh / 2 - (2*c->bw), False); ++ } ++ } ++} +-- +2.1.4 + diff --git a/dwm.suckless.org/patches/dwm-6.1-make-the-borders-of-urgent-windows-a-different-color.diff b/dwm.suckless.org/patches/dwm-6.1-make-the-borders-of-urgent-windows-a-different-color.diff @@ -1,61 +0,0 @@ -From 8b7bc42822cd5924450bbfc9ed598f72254473ba Mon Sep 17 00:00:00 2001 -From: Alexander Huemer <alexander.huemer@xx.vu> -Date: Sat, 7 Mar 2015 21:45:48 +0100 -Subject: [PATCH] Make the borders of urgent windows a different color - ---- - config.def.h | 1 + - dwm.c | 10 ++++++++-- - 2 files changed, 9 insertions(+), 2 deletions(-) - -diff --git a/config.def.h b/config.def.h -index 875885b..5276f02 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -8,6 +8,7 @@ static const char normfgcolor[] = "#bbbbbb"; - static const char selbordercolor[] = "#005577"; - static const char selbgcolor[] = "#005577"; - static const char selfgcolor[] = "#eeeeee"; -+static const char urgbordercolor[] = "#ff0000"; - static const unsigned int borderpx = 1; /* border pixel of windows */ - static const unsigned int snap = 32; /* snap pixel */ - static const Bool showbar = True; /* False means no bar */ -diff --git a/dwm.c b/dwm.c -index c8fc7d7..0924ace 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -58,7 +58,7 @@ - - /* enums */ - enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ --enum { SchemeNorm, SchemeSel, SchemeLast }; /* color schemes */ -+enum { SchemeNorm, SchemeSel, SchemeUrg, SchemeLast }; /* color schemes */ - enum { NetSupported, NetWMName, NetWMState, - NetWMFullscreen, NetActiveWindow, NetWMWindowType, - NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ -@@ -1537,6 +1537,9 @@ setup(void) { - scheme[SchemeSel].border = drw_clr_create(drw, selbordercolor); - scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor); - scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor); -+ scheme[SchemeUrg].border = drw_clr_create(drw, urgbordercolor); -+ scheme[SchemeUrg].bg = drw_clr_create(drw, selbgcolor); -+ scheme[SchemeUrg].fg = drw_clr_create(drw, selfgcolor); - /* init bars */ - updatebars(); - updatestatus(); -@@ -1982,8 +1985,11 @@ updatewmhints(Client *c) { - wmh->flags &= ~XUrgencyHint; - XSetWMHints(dpy, c->win, wmh); - } -- else -+ else { - c->isurgent = (wmh->flags & XUrgencyHint) ? True : False; -+ if (c->isurgent) -+ XSetWindowBorder(dpy, c->win, scheme[SchemeUrg].border->rgb); -+ } - if(wmh->flags & InputHint) - c->neverfocus = !wmh->input; - else --- -2.1.4 - diff --git a/dwm.suckless.org/patches/dwm-6.1-mark.diff b/dwm.suckless.org/patches/dwm-6.1-mark.diff @@ -0,0 +1,231 @@ +diff -Naur dwm-6.1/config.def.h dwm-6.1-patched/config.def.h +--- dwm-6.1/config.def.h 2015-11-09 06:39:37.000000000 +0800 ++++ dwm-6.1-patched/config.def.h 2016-02-17 16:46:11.137603047 +0800 +@@ -11,6 +11,8 @@ + static const char selbordercolor[] = "#005577"; + static const char selbgcolor[] = "#005577"; + static const char selfgcolor[] = "#eeeeee"; ++static const char normmarkcolor[] = "#775500"; ++static const char selmarkcolor[] = "#775577"; + static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const int showbar = 1; /* 0 means no bar */ +@@ -68,7 +70,6 @@ + { MODKEY, XK_d, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, +- { MODKEY, XK_Return, zoom, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY|ShiftMask, XK_c, killclient, {0} }, + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, +@@ -82,6 +83,9 @@ + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, ++ { MODKEY, XK_Return, swapclient, {0} }, ++ { MODKEY, XK_o, swapfocus, {0} }, ++ { MODKEY, XK_semicolon, togglemark, {0} }, + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) +diff -Naur dwm-6.1/drw.h dwm-6.1-patched/drw.h +--- dwm-6.1/drw.h 2015-11-09 06:39:37.000000000 +0800 ++++ dwm-6.1-patched/drw.h 2016-02-17 16:18:47.424219808 +0800 +@@ -23,6 +23,7 @@ + Clr *fg; + Clr *bg; + Clr *border; ++ Clr *mark; + } ClrScheme; + + typedef struct { +diff -Naur dwm-6.1/dwm.c dwm-6.1-patched/dwm.c +--- dwm-6.1/dwm.c 2015-11-09 06:39:37.000000000 +0800 ++++ dwm-6.1-patched/dwm.c 2016-02-17 16:41:55.737595294 +0800 +@@ -201,16 +201,20 @@ + static void setfocus(Client *c); + static void setfullscreen(Client *c, int fullscreen); + static void setlayout(const Arg *arg); ++static void stemark(const Arg *arg); + static void setmfact(const Arg *arg); + static void setup(void); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static void swapclient(const Arg *arg); ++static void swapfocus(const Arg *arg); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *); + static void togglebar(const Arg *arg); + static void togglefloating(const Arg *arg); ++static void togglemark(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); + static void unfocus(Client *c, int setfocus); +@@ -266,6 +270,7 @@ + static Drw *drw; + static Monitor *mons, *selmon; + static Window root; ++static Client *mark; + + /* configuration, allows nested code to access above variables */ + #include "config.h" +@@ -482,6 +487,7 @@ + for (i = 0; i < CurLast; i++) + drw_cur_free(drw, cursor[i]); + for (i = 0; i < SchemeLast; i++) { ++ drw_clr_free(scheme[i].mark); + drw_clr_free(scheme[i].border); + drw_clr_free(scheme[i].bg); + drw_clr_free(scheme[i].fg); +@@ -807,7 +813,12 @@ + detachstack(c); + attachstack(c); + grabbuttons(c, 1); +- XSetWindowBorder(dpy, c->win, scheme[SchemeSel].border->pix); ++ if (c == mark) ++ XSetWindowBorder(dpy, c->win, ++ scheme[SchemeSel].mark->pix); ++ else ++ XSetWindowBorder(dpy, c->win, ++ scheme[SchemeSel].border->pix); + setfocus(c); + } else { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); +@@ -1018,6 +1029,8 @@ + { + if (!selmon->sel) + return; ++ if (mark == selmon->sel) ++ setmark(0); + if (!sendevent(selmon->sel, wmatom[WMDelete])) { + XGrabServer(dpy); + XSetErrorHandler(xerrordummy); +@@ -1065,7 +1078,10 @@ + + wc.border_width = c->bw; + XConfigureWindow(dpy, w, CWBorderWidth, &wc); +- XSetWindowBorder(dpy, w, scheme[SchemeNorm].border->pix); ++ if (c == mark) ++ XSetWindowBorder(dpy, w, scheme[SchemeNorm].mark->pix); ++ else ++ XSetWindowBorder(dpy, w, scheme[SchemeNorm].border->pix); + configure(c); /* propagates border_width, if size doesn't change */ + updatewindowtype(c); + updatesizehints(c); +@@ -1528,6 +1544,23 @@ + drawbar(selmon); + } + ++void ++setmark(Client *c) ++{ ++ if (c == mark) ++ return; ++ if (mark) { ++ XSetWindowBorder(dpy, mark->win, scheme[mark == selmon->sel ++ ? SchemeSel : SchemeNorm].border->pix); ++ mark = 0; ++ } ++ if (c) { ++ XSetWindowBorder(dpy, c->win, scheme[c == selmon->sel ++ ? SchemeSel : SchemeNorm].mark->pix); ++ mark = c; ++ } ++} ++ + /* arg > 1.0 will set mfact absolutly */ + void + setmfact(const Arg *arg) +@@ -1580,9 +1613,11 @@ + cursor[CurResize] = drw_cur_create(drw, XC_sizing); + cursor[CurMove] = drw_cur_create(drw, XC_fleur); + /* init appearance */ ++ scheme[SchemeNorm].mark = drw_clr_create(drw, normmarkcolor); + scheme[SchemeNorm].border = drw_clr_create(drw, normbordercolor); + scheme[SchemeNorm].bg = drw_clr_create(drw, normbgcolor); + scheme[SchemeNorm].fg = drw_clr_create(drw, normfgcolor); ++ scheme[SchemeSel].mark = drw_clr_create(drw, selmarkcolor); + scheme[SchemeSel].border = drw_clr_create(drw, selbordercolor); + scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor); + scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor); +@@ -1646,6 +1681,50 @@ + } + + void ++swapclient(const Arg *arg) ++{ ++ Client *s, *m, t; ++ ++ if (!mark) { ++ zoom(0); ++ return; ++ } ++ s = selmon->sel; ++ m = mark; ++ if (!s || m == s || !selmon->lt[selmon->sellt]->arrange) ++ return; ++ t = *s; ++ strcpy(s->name, m->name); ++ strcpy(m->name, t.name); ++ s->win = m->win; ++ m->win = t.win; ++ XMoveResizeWindow(dpy, s->win, s->x + 2 * sw, s->y, s->w, s->h); ++ arrange(s->mon); ++ XMapWindow(dpy, s->win); ++ XMoveResizeWindow(dpy, m->win, m->x + 2 * sw, m->y, m->w, m->h); ++ arrange(m->mon); ++ XMapWindow(dpy, m->win); ++ ++ selmon->sel = m; ++ mark = s; ++ focus(s); ++ setmark(m); ++} ++ ++void ++swapfocus(const Arg *arg) ++{ ++ Client *t; ++ ++ if (!selmon->sel || !mark || selmon->sel == mark) { ++ return; ++ } ++ t = mark; ++ setmark(selmon->sel); ++ focus(t); ++} ++ ++void + tag(const Arg *arg) + { + if (selmon->sel && arg->ui & TAGMASK) { +@@ -1713,6 +1792,15 @@ + } + + void ++togglemark(const Arg *arg) ++{ ++ if (!selmon->sel) { ++ return; ++ } ++ setmark(selmon->sel == mark ? 0 : selmon->sel); ++} ++ ++void + toggletag(const Arg *arg) + { + unsigned int newtags; +@@ -1745,7 +1833,10 @@ + if (!c) + return; + grabbuttons(c, 0); +- XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].border->pix); ++ if (c == mark) ++ XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].mark->pix); ++ else ++ XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].border->pix); + if (setfocus) { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); diff --git a/dwm.suckless.org/patches/dwm-6.1-pertag-tab-v2b.diff b/dwm.suckless.org/patches/dwm-6.1-pertag-tab-v2b.diff @@ -0,0 +1,841 @@ +diff --git a/config.def.h b/config.def.h +index 7054c06..f0b33c5 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -15,10 +15,21 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ ++/* Display modes of the tab bar: never shown, always shown, shown only in */ ++/* monocle mode in presence of several windows. */ ++/* Modes after showtab_nmodes are disabled */ ++enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always}; ++static const int showtab = showtab_auto; /* Default tab bar show mode */ ++static const Bool toptab = False; /* False means bottom tab bar */ + + /* tagging */ + static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + ++/* default layout per tags */ ++/* The first element is for all-tag view, following i-th element corresponds to */ ++/* tags[i]. Layout is referred using the layouts array index.*/ ++static int def_layouts[1 + LENGTH(tags)] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; ++ + static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class +@@ -62,6 +73,7 @@ static Key keys[] = { + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, + { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_b, togglebar, {0} }, ++ { MODKEY, XK_w, tabmode, {-1} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, +@@ -109,5 +121,6 @@ static Button buttons[] = { + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, ++ { ClkTabBar, 0, Button1, focuswin, {0} }, + }; + +diff --git a/dwm.1 b/dwm.1 +index 6687011..077d92b 100644 +--- a/dwm.1 ++++ b/dwm.1 +@@ -19,14 +19,22 @@ layout applied. + 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. ++Each screen contains two small status bars. ++.P ++One bar 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 ++Another bar contains a tab for each window of the current view and allows ++navigation between windows, especially in the monocle mode. The different ++display modes of this bar are described under the Mod1\-w Keybord command ++section. When a single tag is selected, that tag is indicated in the left corner ++of the tab bar. + .P + dwm draws a small border around windows to indicate the focus state. + .SH OPTIONS +@@ -43,7 +51,8 @@ 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. ++label toggles between tiled and floating layout, click on a window name in the ++tab bar brings focus to that window. + .TP + .B Button3 + click on a tag label adds/removes all windows with that tag to/from the view. +@@ -104,6 +113,12 @@ Increase master area size. + .B Mod1\-h + Decrease master area size. + .TP ++.B Mod1\-w ++Cycle over the tab bar display modes: never displayed, always displayed, ++displayed only in monocle mode when the view contains than one window (auto ++mode). Some display modes can be disabled in the configuration, config.h. In ++the default configuration only "never" and "auto" display modes are enabled. ++.TP + .B Mod1\-Return + Zooms/cycles focused window to/from master area (tiled layouts only). + .TP +diff --git a/dwm.c b/dwm.c +index 0362114..887a839 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -64,7 +64,7 @@ enum { NetSupported, NetWMName, NetWMState, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ +-enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ++enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ + + typedef union { +@@ -111,25 +111,35 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++#define MAXTABS 50 ++ ++typedef struct Pertag Pertag; + struct Monitor { + char ltsymbol[16]; + float mfact; + int nmaster; + int num; + int by; /* bar geometry */ ++ int ty; /* tab bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; + int showbar; ++ int showtab; + int topbar; ++ int toptab; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; ++ Window tabwin; ++ int ntabs; ++ int tab_widths[MAXTABS]; + const Layout *lt[2]; ++ Pertag *pertag; + }; + + typedef struct { +@@ -164,12 +174,15 @@ static void detachstack(Client *c); + static Monitor *dirtomon(int dir); + static void drawbar(Monitor *m); + static void drawbars(void); ++static void drawtab(Monitor *m); ++static void drawtabs(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 void focuswin(const Arg* arg); + static int getrootptr(int *x, int *y); + static long getstate(Window w); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); +@@ -206,6 +219,7 @@ static void setup(void); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static void tabmode(const Arg *arg); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *); +@@ -240,6 +254,7 @@ 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 th = 0; /* tab bar geometry */ + static int (*xerrorxlib)(Display *, XErrorEvent *); + static unsigned int numlockmask = 0; + static void (*handler[LASTEvent]) (XEvent *) = { +@@ -270,6 +285,16 @@ static Window root; + /* configuration, allows nested code to access above variables */ + #include "config.h" + ++struct Pertag { ++ unsigned int curtag, prevtag; /* current and previous tag */ ++ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ ++ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ ++ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ ++ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ ++ Bool showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ ++ Client *prevzooms[LENGTH(tags) + 1]; /* store zoom information */ ++}; ++ + /* compile-time check if all tags fit into an unsigned int bit array. */ + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +@@ -393,6 +418,8 @@ arrange(Monitor *m) + void + arrangemon(Monitor *m) + { ++ updatebarpos(m); ++ XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th); + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); + if (m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); +@@ -442,14 +469,33 @@ buttonpress(XEvent *e) + click = ClkStatusText; + else + click = ClkWinTitle; +- } else if ((c = wintoclient(ev->window))) { ++ } ++ if(ev->window == selmon->tabwin) { ++ i = 0; x = 0; ++ for(c = selmon->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ x += selmon->tab_widths[i]; ++ if (ev->x > x) ++ ++i; ++ else ++ break; ++ if(i >= m->ntabs) break; ++ } ++ if(c) { ++ click = ClkTabBar; ++ arg.ui = i; ++ } ++ } ++ else if((c = wintoclient(ev->window))) { + focus(c); + 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); ++ 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 || click == ClkTabBar) ++ && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg); ++ } + } + + void +@@ -469,23 +515,24 @@ 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); ++ while(m->stack) ++ unmanage(m->stack, False); + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); +- for (i = 0; i < CurLast; i++) +- drw_cur_free(drw, cursor[i]); +- for (i = 0; i < SchemeLast; i++) { +- drw_clr_free(scheme[i].border); +- drw_clr_free(scheme[i].bg); +- drw_clr_free(scheme[i].fg); +- } ++ drw_cur_free(drw, cursor[CurNormal]); ++ drw_cur_free(drw, cursor[CurResize]); ++ drw_cur_free(drw, cursor[CurMove]); ++ drw_clr_free(scheme[SchemeNorm].border); ++ drw_clr_free(scheme[SchemeNorm].bg); ++ drw_clr_free(scheme[SchemeNorm].fg); ++ drw_clr_free(scheme[SchemeSel].border); ++ drw_clr_free(scheme[SchemeSel].bg); ++ drw_clr_free(scheme[SchemeSel].fg); + drw_free(drw); + XSync(dpy, False); + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); +@@ -505,6 +552,8 @@ cleanupmon(Monitor *mon) + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); ++ XUnmapWindow(dpy, mon->tabwin); ++ XDestroyWindow(dpy, mon->tabwin); + free(mon); + } + +@@ -526,6 +575,7 @@ clientmessage(XEvent *e) + { + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); ++ int i; + + if (!c) + return; +@@ -537,6 +587,8 @@ clientmessage(XEvent *e) + if (!ISVISIBLE(c)) { + c->mon->seltags ^= 1; + c->mon->tagset[c->mon->seltags] = c->tags; ++ for(i=0; !(c->tags & 1 << i); i++); ++ view(&(Arg){.ui = 1 << i}); + } + pop(c); + } +@@ -565,6 +617,7 @@ void + configurenotify(XEvent *e) + { + Monitor *m; ++ Client *c; + XConfigureEvent *ev = &e->xconfigure; + int dirty; + +@@ -576,8 +629,14 @@ configurenotify(XEvent *e) + if (updategeom() || dirty) { + drw_resize(drw, sw, bh); + updatebars(); +- for (m = mons; m; m = m->next) ++ //refreshing display of status bar. The tab bar is handled by the arrange() ++ //method, which is called below ++ for(m = mons; m; m = m->next){ ++ for (c = m->clients; c; c = c->next) ++ if (c->isfullscreen) ++ resizeclient(c, m->mx, m->my, m->mw, m->mh); + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); ++ } + focus(NULL); + arrange(NULL); + } +@@ -640,16 +699,41 @@ Monitor * + createmon(void) + { + Monitor *m; ++ int i; + + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; + m->mfact = mfact; + m->nmaster = nmaster; + m->showbar = showbar; ++ m->showtab = showtab; + m->topbar = topbar; +- m->lt[0] = &layouts[0]; ++ m->toptab = toptab; ++ m->ntabs = 0; ++ m->lt[0] = &layouts[def_layouts[1] % LENGTH(layouts)]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); ++ if(!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Pertag)); ++ m->pertag->curtag = m->pertag->prevtag = 1; ++ for(i=0; i <= LENGTH(tags); i++) { ++ /* init nmaster */ ++ m->pertag->nmasters[i] = m->nmaster; ++ ++ /* init mfacts */ ++ m->pertag->mfacts[i] = m->mfact; ++ ++ /* init layouts */ ++ m->pertag->ltidxs[i][0] = &layouts[def_layouts[i % LENGTH(def_layouts)] % LENGTH(layouts)]; ++ m->pertag->ltidxs[i][1] = m->lt[1]; ++ m->pertag->sellts[i] = m->sellt; ++ ++ /* init showbar */ ++ m->pertag->showbars[i] = m->showbar; ++ ++ /* swap focus and zoomswap*/ ++ m->pertag->prevzooms[i] = NULL; ++ } + return m; + } + +@@ -763,6 +847,104 @@ drawbars(void) + } + + void ++drawtabs(void) { ++ Monitor *m; ++ ++ for(m = mons; m; m = m->next) ++ drawtab(m); ++} ++ ++static int ++cmpint(const void *p1, const void *p2) { ++ /* The actual arguments to this function are "pointers to ++ pointers to char", but strcmp(3) arguments are "pointers ++ to char", hence the following cast plus dereference */ ++ return *((int*) p1) > * (int*) p2; ++} ++ ++ ++void ++drawtab(Monitor *m) { ++ Client *c; ++ int i; ++ int itag = -1; ++ char view_info[50]; ++ int view_info_w = 0; ++ int sorted_label_widths[MAXTABS]; ++ int tot_width; ++ int maxsize = bh; ++ int x = 0; ++ int w = 0; ++ ++ //view_info: indicate the tag which is displayed in the view ++ for(i = 0; i < LENGTH(tags); ++i){ ++ if((selmon->tagset[selmon->seltags] >> i) & 1) { ++ if(itag >=0){ //more than one tag selected ++ itag = -1; ++ break; ++ } ++ itag = i; ++ } ++ } ++ if(0 <= itag && itag < LENGTH(tags)){ ++ snprintf(view_info, sizeof view_info, "[%s]", tags[itag]); ++ } else { ++ strncpy(view_info, "[...]", sizeof view_info); ++ } ++ view_info[sizeof(view_info) - 1 ] = 0; ++ view_info_w = TEXTW(view_info); ++ tot_width = view_info_w; ++ ++ /* Calculates number of labels and their width */ ++ m->ntabs = 0; ++ for(c = m->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ m->tab_widths[m->ntabs] = TEXTW(c->name); ++ tot_width += m->tab_widths[m->ntabs]; ++ ++m->ntabs; ++ if(m->ntabs >= MAXTABS) break; ++ } ++ ++ if(tot_width > m->ww){ //not enough space to display the labels, they need to be truncated ++ memcpy(sorted_label_widths, m->tab_widths, sizeof(int) * m->ntabs); ++ qsort(sorted_label_widths, m->ntabs, sizeof(int), cmpint); ++ tot_width = view_info_w; ++ for(i = 0; i < m->ntabs; ++i){ ++ if(tot_width + (m->ntabs - i) * sorted_label_widths[i] > m->ww) ++ break; ++ tot_width += sorted_label_widths[i]; ++ } ++ maxsize = (m->ww - tot_width) / (m->ntabs - i); ++ } else{ ++ maxsize = m->ww; ++ } ++ i = 0; ++ for(c = m->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ if(i >= m->ntabs) break; ++ if(m->tab_widths[i] > maxsize) m->tab_widths[i] = maxsize; ++ w = m->tab_widths[i]; ++ drw_setscheme(drw, (c == m->sel) ? &scheme[SchemeSel] : &scheme[SchemeNorm]); ++ drw_text(drw, x, 0, w, th, c->name, 0); ++ x += w; ++ ++i; ++ } ++ ++ drw_setscheme(drw, &scheme[SchemeNorm]); ++ ++ /* cleans interspace between window names and current viewed tag label */ ++ w = m->ww - view_info_w - x; ++ drw_text(drw, x, 0, w, th, "", 0); ++ ++ /* view info */ ++ x += w; ++ w = view_info_w; ++ drw_text(drw, x, 0, w, th, view_info, 0); ++ ++ drw_map(drw, m->tabwin, 0, 0, m->ww, th); ++} ++ ++void + enternotify(XEvent *e) + { + Client *c; +@@ -787,8 +969,10 @@ 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); ++ drawtab(m); ++ } + } + + void +@@ -806,7 +990,7 @@ focus(Client *c) + clearurgent(c); + detachstack(c); + attachstack(c); +- grabbuttons(c, 1); ++ grabbuttons(c, True); + XSetWindowBorder(dpy, c->win, scheme[SchemeSel].border->pix); + setfocus(c); + } else { +@@ -815,6 +999,7 @@ focus(Client *c) + } + selmon->sel = c; + drawbars(); ++ drawtabs(); + } + + /* there are some broken focus acquiring clients */ +@@ -868,6 +1053,19 @@ focusstack(const Arg *arg) + } + } + ++void ++focuswin(const Arg* arg){ ++ int iwin = arg->i; ++ Client* c = NULL; ++ for(c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next){ ++ if(ISVISIBLE(c)) --iwin; ++ }; ++ if(c) { ++ focus(c); ++ restack(selmon); ++ } ++} ++ + Atom + getatomprop(Client *c, Atom prop) + { +@@ -981,7 +1179,7 @@ grabkeys(void) + void + incnmaster(const Arg *arg) + { +- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); + } + +@@ -1139,7 +1337,7 @@ motionnotify(XEvent *e) + if (ev->window != root) + return; + if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { +- unfocus(selmon->sel, 1); ++ unfocus(selmon->sel, True); + selmon = m; + focus(NULL); + } +@@ -1159,11 +1357,13 @@ movemouse(const Arg *arg) + return; + if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ + 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) ++ None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) + return; + if (!getrootptr(&x, &y)) + return; +@@ -1250,12 +1450,14 @@ propertynotify(XEvent *e) + case XA_WM_HINTS: + updatewmhints(c); + drawbars(); ++ drawtabs(); + break; + } + if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { + updatetitle(c); + if (c == c->mon->sel) + drawbar(c->mon); ++ drawtab(c->mon); + } + if (ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); +@@ -1317,11 +1519,13 @@ resizemouse(const Arg *arg) + return; + if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ + 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) ++ 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 { +@@ -1369,6 +1573,7 @@ restack(Monitor *m) + XWindowChanges wc; + + drawbar(m); ++ drawtab(m); + if (!m->sel) + return; + if (m->sel->isfloating || !m->lt[m->sellt]->arrange) +@@ -1477,11 +1682,11 @@ sendevent(Client *c, Atom proto) + void + setfocus(Client *c) + { +- if (!c->neverfocus) { ++ if(!c->neverfocus) { + XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); + XChangeProperty(dpy, root, netatom[NetActiveWindow], +- XA_WINDOW, 32, PropModeReplace, +- (unsigned char *) &(c->win), 1); ++ XA_WINDOW, 32, PropModeReplace, ++ (unsigned char *) &(c->win), 1); + } + sendevent(c, wmatom[WMTakeFocus]); + } +@@ -1517,10 +1722,13 @@ setfullscreen(Client *c, int fullscreen) + 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; ++ if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) { ++ selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ } ++ if(arg && arg->v) ++ selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if (selmon->sel) + arrange(selmon); +@@ -1539,7 +1747,7 @@ setmfact(const Arg *arg) + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if (f < 0.1 || f > 0.9) + return; +- selmon->mfact = f; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; + arrange(selmon); + } + +@@ -1559,8 +1767,9 @@ setup(void) + drw = drw_create(dpy, screen, root, sw, sh); + drw_load_fonts(drw, fonts, LENGTH(fonts)); + if (!drw->fontcount) +- die("no fonts could be loaded.\n"); ++ die("No fonts could be loaded.\n"); + bh = drw->fonts[0]->h + 2; ++ th = bh; + updategeom(); + /* init atoms */ + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); +@@ -1632,10 +1841,10 @@ sigchld(int unused) + void + spawn(const Arg *arg) + { +- if (arg->v == dmenucmd) ++ if(arg->v == dmenucmd) + dmenumon[0] = '0' + selmon->num; +- if (fork() == 0) { +- if (dpy) ++ if(fork() == 0) { ++ if(dpy) + close(ConnectionNumber(dpy)); + setsid(); + execvp(((char **)arg->v)[0], (char **)arg->v); +@@ -1692,18 +1901,29 @@ tile(Monitor *m) + void + togglebar(const Arg *arg) + { +- selmon->showbar = !selmon->showbar; ++ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; + updatebarpos(selmon); + XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); + arrange(selmon); + } + + void ++tabmode(const Arg *arg) ++{ ++ if(arg && arg->i >= 0) ++ selmon->showtab = arg->ui % showtab_nmodes; ++ else ++ selmon->showtab = (selmon->showtab + 1 ) % showtab_nmodes; ++ arrange(selmon); ++} ++ ++ ++void + togglefloating(const Arg *arg) + { +- if (!selmon->sel) ++ if(!selmon->sel) + return; +- if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ ++ if(selmon->sel->isfullscreen) /* no support for fullscreen windows */ + return; + selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed; + if (selmon->sel->isfloating) +@@ -1731,9 +1951,29 @@ void + toggleview(const Arg *arg) + { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); ++ int i; + + if (newtagset) { ++ if(newtagset == ~0) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = 0; ++ } ++ /* test if the user did not select the same tag */ ++ if(!(newtagset & 1 << (selmon->pertag->curtag - 1))) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ for (i=0; !(newtagset & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } + selmon->tagset[selmon->seltags] = newtagset; ++ ++ /* apply settings for this view */ ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); + focus(NULL); + arrange(selmon); + } +@@ -1744,7 +1984,7 @@ unfocus(Client *c, int setfocus) + { + if (!c) + return; +- grabbuttons(c, 0); ++ grabbuttons(c, False); + XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].border->pix); + if (setfocus) { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); +@@ -1809,20 +2049,44 @@ updatebars(void) + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); + XMapRaised(dpy, m->barwin); ++ m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen), ++ CopyFromParent, DefaultVisual(dpy, screen), ++ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); ++ XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor); ++ XMapRaised(dpy, m->tabwin); + } + } + + void + updatebarpos(Monitor *m) + { ++ Client *c; ++ int nvis = 0; ++ + 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 ++ if ( m->topbar ) ++ m->wy += bh; ++ } else { + m->by = -bh; ++ } ++ ++ for(c = m->clients; c; c = c->next){ ++ if(ISVISIBLE(c)) ++nvis; ++ } ++ ++ if(m->showtab == showtab_always ++ || ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->sellt]->arrange == monocle))){ ++ m->wh -= th; ++ m->ty = m->toptab ? m->wy : m->wy + m->wh; ++ if ( m->toptab ) ++ m->wy += th; ++ } else { ++ m->ty = -th; ++ } + } + + void +@@ -2004,9 +2268,9 @@ updatewindowtype(Client *c) + Atom wtype = getatomprop(c, netatom[NetWMWindowType]); + + if (state == netatom[NetWMFullscreen]) +- setfullscreen(c, 1); ++ setfullscreen(c, True); + if (wtype == netatom[NetWMWindowTypeDialog]) +- c->isfloating = 1; ++ c->isfloating = True; + } + + void +@@ -2031,11 +2295,33 @@ updatewmhints(Client *c) + void + view(const Arg *arg) + { +- if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) ++ int i; ++ unsigned int tmptag; ++ ++ if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ +- if (arg->ui & TAGMASK) ++ if(arg->ui & TAGMASK) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; ++ if(arg->ui == ~0) ++ selmon->pertag->curtag = 0; ++ else { ++ for (i=0; !(arg->ui & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } ++ } else { ++ tmptag = selmon->pertag->prevtag; ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = tmptag; ++ } ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); + focus(NULL); + arrange(selmon); + } +@@ -2063,7 +2349,7 @@ wintomon(Window w) + if (w == root && getrootptr(&x, &y)) + return recttomon(x, y, 1, 1); + for (m = mons; m; m = m->next) +- if (w == m->barwin) ++ if(w == m->barwin || w == m->tabwin) + return m; + if ((c = wintoclient(w))) + return c->mon; diff --git a/dwm.suckless.org/patches/dwm-6.1-pertag.diff b/dwm.suckless.org/patches/dwm-6.1-pertag.diff @@ -1,15 +1,8 @@ -Author: Jan Christoph Ebersbach <jceb@e-jc.de> -URL: http://dwm.suckless.org/patches/pertag -This patch keeps layout, mwfact, barpos and nmaster per tag. - -Contributors: -- Carlos Pita, thanks for debugging NetActiveWindow issues and sending a patch - -Index: dwm/dwm.c -=================================================================== ---- dwm/dwm.c.orig 2014-02-09 15:24:18.232117136 +0100 -+++ dwm/dwm.c 2014-02-09 15:24:18.224117135 +0100 -@@ -110,6 +110,7 @@ +diff --git a/dwm.c b/dwm.c +index 0362114..9ba4ec5 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -111,6 +111,7 @@ typedef struct { void (*arrange)(Monitor *); } Layout; @@ -17,7 +10,7 @@ Index: dwm/dwm.c struct Monitor { char ltsymbol[16]; float mfact; -@@ -129,6 +130,7 @@ +@@ -130,6 +131,7 @@ struct Monitor { Monitor *next; Window barwin; const Layout *lt[2]; @@ -25,7 +18,7 @@ Index: dwm/dwm.c }; typedef struct { -@@ -270,6 +272,16 @@ +@@ -270,6 +272,16 @@ static Window root; /* configuration, allows nested code to access above variables */ #include "config.h" @@ -42,16 +35,16 @@ Index: dwm/dwm.c /* compile-time check if all tags fit into an unsigned int bit array. */ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; -@@ -518,6 +530,7 @@ - clientmessage(XEvent *e) { +@@ -526,6 +538,7 @@ clientmessage(XEvent *e) + { XClientMessageEvent *cme = &e->xclient; Client *c = wintoclient(cme->window); + int i; - if(!c) + if (!c) return; -@@ -530,6 +543,8 @@ - if(!ISVISIBLE(c)) { +@@ -537,6 +550,8 @@ clientmessage(XEvent *e) + if (!ISVISIBLE(c)) { c->mon->seltags ^= 1; c->mon->tagset[c->mon->seltags] = c->tags; + for(i=0; !(c->tags & 1 << i); i++); @@ -59,19 +52,19 @@ Index: dwm/dwm.c } pop(c); } -@@ -631,6 +646,7 @@ - Monitor * - createmon(void) { +@@ -640,6 +655,7 @@ Monitor * + createmon(void) + { Monitor *m; + int i; - if(!(m = (Monitor *)calloc(1, sizeof(Monitor)))) - die("fatal: could not malloc() %u bytes\n", sizeof(Monitor)); -@@ -642,6 +658,27 @@ + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; +@@ -650,6 +666,27 @@ createmon(void) m->lt[0] = &layouts[0]; m->lt[1] = &layouts[1 % LENGTH(layouts)]; strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); -+ if(!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag)))) ++ if (!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag)))) + die("fatal: could not malloc() %u bytes\n", sizeof(Pertag)); + m->pertag->curtag = m->pertag->prevtag = 1; + for(i=0; i <= LENGTH(tags); i++) { @@ -95,63 +88,63 @@ Index: dwm/dwm.c return m; } -@@ -958,7 +995,7 @@ - +@@ -981,7 +1018,7 @@ grabkeys(void) void - incnmaster(const Arg *arg) { + incnmaster(const Arg *arg) + { - selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); arrange(selmon); } -@@ -1462,10 +1499,13 @@ - +@@ -1517,10 +1554,13 @@ setfullscreen(Client *c, int fullscreen) void - setlayout(const Arg *arg) { -- if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) + setlayout(const Arg *arg) + { +- if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) - selmon->sellt ^= 1; -+ if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) { ++ if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) { + selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; + } - if(arg && arg->v) + if (arg && arg->v) - selmon->lt[selmon->sellt] = (Layout *)arg->v; + selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); - if(selmon->sel) + if (selmon->sel) arrange(selmon); -@@ -1483,7 +1523,7 @@ +@@ -1539,7 +1579,7 @@ setmfact(const Arg *arg) f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; - if(f < 0.1 || f > 0.9) + if (f < 0.1 || f > 0.9) return; - selmon->mfact = f; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; arrange(selmon); } -@@ -1627,7 +1667,7 @@ - +@@ -1692,7 +1732,7 @@ tile(Monitor *m) void - togglebar(const Arg *arg) { + togglebar(const Arg *arg) + { - selmon->showbar = !selmon->showbar; + selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; updatebarpos(selmon); XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); arrange(selmon); -@@ -1663,9 +1703,29 @@ - void - toggleview(const Arg *arg) { +@@ -1731,9 +1771,29 @@ void + toggleview(const Arg *arg) + { unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + int i; - if(newtagset) { -+ if(newtagset == ~0) { + if (newtagset) { ++ if (newtagset == ~0) { + selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->pertag->curtag = 0; + } + /* test if the user did not select the same tag */ -+ if(!(newtagset & 1 << (selmon->pertag->curtag - 1))) { ++ if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) { + selmon->pertag->prevtag = selmon->pertag->curtag; + for (i=0; !(newtagset & 1 << i); i++) ; + selmon->pertag->curtag = i + 1; @@ -169,21 +162,21 @@ Index: dwm/dwm.c focus(NULL); arrange(selmon); } -@@ -1960,11 +2020,33 @@ - +@@ -2031,11 +2091,33 @@ updatewmhints(Client *c) void - view(const Arg *arg) { + view(const Arg *arg) + { + int i; + unsigned int tmptag; + - if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) return; selmon->seltags ^= 1; /* toggle sel tagset */ -- if(arg->ui & TAGMASK) -+ if(arg->ui & TAGMASK) { +- if (arg->ui & TAGMASK) ++ if (arg->ui & TAGMASK) { + selmon->pertag->prevtag = selmon->pertag->curtag; selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; -+ if(arg->ui == ~0) ++ if (arg->ui == ~0) + selmon->pertag->curtag = 0; + else { + for (i=0; !(arg->ui & 1 << i); i++) ; diff --git a/dwm.suckless.org/patches/dwm-6.1-pertag_without_bar.diff b/dwm.suckless.org/patches/dwm-6.1-pertag_without_bar.diff @@ -0,0 +1,161 @@ +diff --git a/dwm.c b/dwm.c +index 0362114..e44bb24 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -111,6 +111,7 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++typedef struct Pertag Pertag; + struct Monitor { + char ltsymbol[16]; + float mfact; +@@ -130,6 +131,7 @@ struct Monitor { + Monitor *next; + Window barwin; + const Layout *lt[2]; ++ Pertag *pertag; + }; + + typedef struct { +@@ -270,6 +272,14 @@ static Window root; + /* configuration, allows nested code to access above variables */ + #include "config.h" + ++struct Pertag { ++ unsigned int curtag, prevtag; /* current and previous tag */ ++ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ ++ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ ++ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ ++ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ ++}; ++ + /* compile-time check if all tags fit into an unsigned int bit array. */ + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +@@ -640,6 +650,7 @@ Monitor * + createmon(void) + { + Monitor *m; ++ int i; + + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; +@@ -650,6 +661,21 @@ createmon(void) + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); ++ if (!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Pertag)); ++ m->pertag->curtag = m->pertag->prevtag = 1; ++ for (i=0; i <= LENGTH(tags); i++) { ++ /* init nmaster */ ++ m->pertag->nmasters[i] = m->nmaster; ++ ++ /* init mfacts */ ++ m->pertag->mfacts[i] = m->mfact; ++ ++ /* init layouts */ ++ m->pertag->ltidxs[i][0] = m->lt[0]; ++ m->pertag->ltidxs[i][1] = m->lt[1]; ++ m->pertag->sellts[i] = m->sellt; ++ } + return m; + } + +@@ -981,7 +1007,7 @@ grabkeys(void) + void + incnmaster(const Arg *arg) + { +- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); + } + +@@ -1517,10 +1543,13 @@ setfullscreen(Client *c, int fullscreen) + void + setlayout(const Arg *arg) + { +- if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) +- selmon->sellt ^= 1; ++ if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) { ++ selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ } + if (arg && arg->v) +- selmon->lt[selmon->sellt] = (Layout *)arg->v; ++ selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if (selmon->sel) + arrange(selmon); +@@ -1539,7 +1568,7 @@ setmfact(const Arg *arg) + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if (f < 0.1 || f > 0.9) + return; +- selmon->mfact = f; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; + arrange(selmon); + } + +@@ -1731,9 +1760,27 @@ void + toggleview(const Arg *arg) + { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); ++ int i; + + if (newtagset) { ++ if (newtagset == ~0) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = 0; ++ } ++ /* test if the user did not select the same tag */ ++ if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ for (i=0; !(newtagset & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } + selmon->tagset[selmon->seltags] = newtagset; ++ ++ /* apply settings for this view */ ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; + focus(NULL); + arrange(selmon); + } +@@ -2031,11 +2078,31 @@ updatewmhints(Client *c) + void + view(const Arg *arg) + { ++ int i; ++ unsigned int tmptag; ++ + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ +- if (arg->ui & TAGMASK) ++ if (arg->ui & TAGMASK) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; ++ if (arg->ui == ~0) ++ selmon->pertag->curtag = 0; ++ else { ++ for (i=0; !(arg->ui & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } ++ } else { ++ tmptag = selmon->pertag->prevtag; ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = tmptag; ++ } ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; + focus(NULL); + arrange(selmon); + } diff --git a/dwm.suckless.org/patches/dwm-6.1-push_no_master.diff b/dwm.suckless.org/patches/dwm-6.1-push_no_master.diff @@ -0,0 +1,70 @@ +diff --git a/dwm.c b/dwm.c +index 0362114..d61d736 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -186,7 +186,10 @@ static void motionnotify(XEvent *e); + static void movemouse(const Arg *arg); + static Client *nexttiled(Client *c); + static void pop(Client *); ++static Client *prevtiled(Client *c); + static void propertynotify(XEvent *e); ++static void pushdown(const Arg *arg); ++static void pushup(const Arg *arg); + static void quit(const Arg *arg); + static Monitor *recttomon(int x, int y, int w, int h); + static void resize(Client *c, int x, int y, int w, int h, int interact); +@@ -1225,6 +1228,16 @@ pop(Client *c) + arrange(c->mon); + } + ++Client * ++prevtiled(Client *c) { ++ Client *p, *r; ++ ++ for(p = selmon->clients, r = NULL; p && p != c; p = p->next) ++ if(!p->isfloating && ISVISIBLE(p)) ++ r = p; ++ return r; ++} ++ + void + propertynotify(XEvent *e) + { +@@ -1263,6 +1276,37 @@ propertynotify(XEvent *e) + } + + void ++pushdown(const Arg *arg) { ++ Client *sel = selmon->sel, *c; ++ ++ if(!sel || sel->isfloating || sel == nexttiled(selmon->clients)) ++ return; ++ if((c = nexttiled(sel->next))) { ++ detach(sel); ++ sel->next = c->next; ++ c->next = sel; ++ } ++ focus(sel); ++ arrange(selmon); ++} ++ ++void ++pushup(const Arg *arg) { ++ Client *sel = selmon->sel, *c; ++ ++ if(!sel || sel->isfloating) ++ return; ++ if((c = prevtiled(sel)) && c != nexttiled(selmon->clients)) { ++ detach(sel); ++ sel->next = c; ++ for(c = selmon->clients; c->next != sel->next; c = c->next); ++ c->next = sel; ++ } ++ focus(sel); ++ arrange(selmon); ++} ++ ++void + quit(const Arg *arg) + { + running = 0; diff --git a/dwm.suckless.org/patches/dwm-6.1-resizecorners.diff b/dwm.suckless.org/patches/dwm-6.1-resizecorners.diff @@ -0,0 +1,68 @@ +diff --git a/dwm.c b/dwm.c +index ff7e096..b6ce27c 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -1313,9 +1313,14 @@ void + resizemouse(const Arg *arg) + { + int ocx, ocy, nw, nh; ++ int ocx2, ocy2, nx, ny; + Client *c; + Monitor *m; + XEvent ev; ++ int horizcorner, vertcorner; ++ int di; ++ unsigned int dui; ++ Window dummy; + Time lasttime = 0; + + if (!(c = selmon->sel)) +@@ -1325,10 +1330,19 @@ resizemouse(const Arg *arg) + restack(selmon); + ocx = c->x; + ocy = c->y; ++ ocx2 = c->x + c->w; ++ ocy2 = c->y + c->h; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, + None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess) + return; +- XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); ++ if (!XQueryPointer (dpy, c->win, &dummy, &dummy, &di, &di, &nx, &ny, &dui)) ++ return; ++ horizcorner = nx < c->w / 2; ++ vertcorner = ny < c->h / 2; ++ XWarpPointer (dpy, None, c->win, 0, 0, 0, 0, ++ horizcorner ? (-c->bw) : (c->w + c->bw - 1), ++ vertcorner ? (-c->bw) : (c->h + c->bw - 1)); ++ + do { + XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); + switch(ev.type) { +@@ -1344,6 +1358,11 @@ resizemouse(const Arg *arg) + + nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); + nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); ++ nx = horizcorner ? ev.xmotion.x : c->x; ++ ny = vertcorner ? ev.xmotion.y : c->y; ++ nw = MAX(horizcorner ? (ocx2 - nx) : (ev.xmotion.x - ocx - 2 * c->bw + 1), 1); ++ nh = MAX(vertcorner ? (ocy2 - ny) : (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) + { +@@ -1352,11 +1371,13 @@ resizemouse(const Arg *arg) + togglefloating(NULL); + } + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) +- resize(c, c->x, c->y, nw, nh, 1); ++ resize(c, nx, ny, 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); ++ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, ++ horizcorner ? (-c->bw) : (c->w + c->bw - 1), ++ vertcorner ? (-c->bw) : (c->h + c->bw - 1)); + XUngrabPointer(dpy, CurrentTime); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); + if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { diff --git a/dwm.suckless.org/patches/dwm-6.1-single_window_no_border.diff b/dwm.suckless.org/patches/dwm-6.1-single_window_no_border.diff @@ -3,25 +3,23 @@ URL: http://dwm.suckless.org/patches/noborder This patch removes the border when there is just one window visible in tiled or monocle layout. -Index: dwm/dwm.c -=================================================================== ---- dwm/dwm.c.orig 2014-02-09 15:24:19.404117168 +0100 -+++ dwm/dwm.c 2014-02-09 15:24:19.396117168 +0100 -@@ -1089,7 +1089,7 @@ - +--- dwm/dwm.c.orig 2015-11-11 19:14:39.771079356 -0800 ++++ dwm/dwm.c 2015-11-11 19:14:42.821079144 -0800 +@@ -1117,7 +1117,7 @@ maprequest(XEvent *e) void - monocle(Monitor *m) { + monocle(Monitor *m) + { - unsigned int n = 0; + unsigned int n = 0, r = 0; Client *c; - for(c = m->clients; c; c = c->next) -@@ -1097,8 +1097,17 @@ + for (c = m->clients; c; c = c->next) +@@ -1125,8 +1125,17 @@ monocle(Monitor *m) n++; - if(n > 0) /* override layout symbol */ + 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, False); +- 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); + for(c = nexttiled(m->clients); c; c = nexttiled(c->next)) { + /* remove border when in monocle layout */ + if(c->bw) { @@ -29,31 +27,31 @@ Index: dwm/dwm.c + c->bw = 0; + r = 1; + } -+ resize(c, m->wx, m->wy, m->ww - (2 * c->bw), m->wh - (2 * c->bw), False); ++ resize(c, m->wx, m->wy, m->ww - (2 * c->bw), m->wh - (2 * c->bw), False); + if(r) -+ resizeclient(c, m->wx, m->wy, m->ww - (2 * c->bw), m->wh - (2 * c->bw)); ++ resizeclient(c, m->wx, m->wy, m->ww - (2 * c->bw), m->wh - (2 * c->bw)); + } } void -@@ -1601,7 +1610,7 @@ - +@@ -1666,7 +1675,7 @@ tagmon(const Arg *arg) void - tile(Monitor *m) { + tile(Monitor *m) + { - unsigned int i, n, h, mw, my, ty; + unsigned int i, n, h, mw, my, ty, r; Client *c; - for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); -@@ -1612,17 +1621,36 @@ + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); +@@ -1677,16 +1686,35 @@ tile(Monitor *m) 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++) -+ for(i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++, r = 0) { +- for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { + if(n == 1) { + if (c->bw) { -+ /* remove border when only one window is on the current tag */ ++ /* remove border when only one window is on the cu rrent tag */ + c->oldbw = c->bw; + c->bw = 0; + r = 1; @@ -65,16 +63,15 @@ Index: dwm/dwm.c + c->oldbw = 0; + r = 1; + } - if(i < m->nmaster) { + if (i < m->nmaster) { h = (m->wh - my) / (MIN(n, m->nmaster) - i); - resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False); + resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); + if(r) + resizeclient(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw)); my += HEIGHT(c); - } - else { + } 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), False); + resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); + if(r) + resizeclient(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw)); ty += HEIGHT(c); @@ -83,19 +80,19 @@ Index: dwm/dwm.c } void -@@ -1640,9 +1668,15 @@ - if(selmon->sel->isfullscreen) /* no support for fullscreen windows */ +@@ -1706,9 +1734,15 @@ togglefloating(const Arg *arg) + if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ return; selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed; -- if(selmon->sel->isfloating) -+ if(selmon->sel->isfloating) { +- if (selmon->sel->isfloating) ++ if (selmon->sel->isfloating) { + /* restore border when moving window into floating mode */ + if(!selmon->sel->bw && selmon->sel->oldbw) { + selmon->sel->bw = selmon->sel->oldbw; + selmon->sel->oldbw = 0; + } resize(selmon->sel, selmon->sel->x, selmon->sel->y, - selmon->sel->w, selmon->sel->h, False); + selmon->sel->w, selmon->sel->h, 0); + } arrange(selmon); } diff --git a/dwm.suckless.org/patches/dwm-6.1-statuscolors.diff b/dwm.suckless.org/patches/dwm-6.1-statuscolors.diff @@ -1,100 +1,90 @@ -Only in dwm: config.def.h -diff -up dwm/drw.c dwm_git_colors/drw.c ---- dwm/drw.c 2015-03-24 10:00:33.865796838 -0700 -+++ dwm_git_colors/drw.c 2015-03-24 09:56:59.542647284 -0700 -@@ -202,13 +202,38 @@ drw_setscheme(Drw *drw, ClrScheme *schem - drw->scheme = scheme; +diff -up dwm/drw.c dwm-statuscolors/drw.c +--- dwm/drw.c 2015-11-08 15:39:37.000000000 -0700 ++++ dwm-statuscolors/drw.c 2015-11-28 15:42:28.534399525 -0700 +@@ -206,6 +206,68 @@ drw_setscheme(Drw *drw, ClrScheme *schem + drw->scheme = scheme; } +int -+drw_colored_text(Drw *drw, ClrScheme *scheme, int numcolors, int x, int y, unsigned int w, unsigned int h, char *text) { -+ if(!drw || !drw->fontcount || !drw->scheme) -+ return 0; ++drw_get_width(Drw *drw, int numcolors, const char *text) ++{ ++ int i; ++ Fnt *curfont = drw->fonts[0]; ++ int w = drw_text(drw, 0, 0, 0, 0, text, 0) + curfont->h; ++ ++ for (i = 0; i < strlen(text); i++) { ++ if (text[i] > 0 && text[i] <= numcolors) { ++ /* we found a color code ++ * drw_text counted it as a normal character and added one character's width ++ * we aren't going to render this character, so we remove one character's width */ ++ w -= curfont->xfont->max_advance_width; ++ ++ if (i == 0 || i + 1 == strlen(text)) { ++ /* we're on the first or the last character of the string ++ * drw_text already added one character's height (divided by 2) as padding to the beginning and end ++ * we don't want to double this padding, so we skip this character */ ++ continue; ++ } ++ ++ if (text[i - 1] > 0 && text[i - 1] <= numcolors) { ++ /* the previous character was also a color code ++ * we already added padding in the previous iteration ++ * we don't want to double this padding, so we skip this character */ ++ continue; ++ } ++ ++ /* we are somewhere in the middle of the string and the color has changed ++ * we want to add one character's height (divided by 2) as padding to the end of the previous colored text ++ * and to the beginning of the new colored text */ ++ w += curfont->h; ++ } ++ } ++ ++ return w; ++} + -+ char *buf = text, *ptr = buf, c =1; ++void ++drw_colored_text(Drw *drw, ClrScheme *scheme, int numcolors, int x, int y, unsigned int w, unsigned int h, char *text) ++{ ++ if (!drw || !drw->fontcount || !drw->scheme) ++ return; ++ ++ char *buf = text, *ptr = buf, c = 1; + int i; + -+ while(*ptr) { -+ for(i = 0; *ptr < 0 || *ptr > numcolors; i++, ptr++); -+ if(!*ptr) ++ while (*ptr) { ++ for (i = 0; *ptr < 0 || *ptr > numcolors; i++, ptr++); ++ if (!*ptr) + break; + c = *ptr; + *ptr = 0; -+ if(i) { -+ x = drw_text(drw, x, y, w, h, buf, 0); -+ } ++ if (i) ++ x = drw_text(drw, x, y, w, h, buf, 0) + drw->fonts[0]->h; + *ptr = c; + drw_setscheme(drw, &scheme[c-1]); + buf = ++ptr; + } + drw_text(drw, x, y, w, h, buf, 0); -+ return x; +} + void --drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert) { -+drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty) { - int dx; - - if(!drw || !drw->fontcount || !drw->scheme) - return; -- XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->bg->pix : drw->scheme->fg->pix); -+ XSetForeground(drw->dpy, drw->gc, drw->scheme->fg->pix); - dx = (drw->fonts[0]->ascent + drw->fonts[0]->descent + 2) / 4; - if(filled) - XFillRectangle(drw->dpy, drw->drawable, drw->gc, x+1, y+1, dx+1, dx+1); -@@ -217,7 +242,7 @@ drw_rect(Drw *drw, int x, int y, unsigne - } - - int --drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int invert) { -+drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int pad) { - char buf[1024]; - int tx, ty, th; - Extnts tex; -@@ -242,7 +267,7 @@ drw_text(Drw *drw, int x, int y, unsigne - if (!drw || !drw->scheme) { - return 0; - } else if (render) { -- XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->fg->pix : drw->scheme->bg->pix); -+ XSetForeground(drw->dpy, drw->gc, drw->scheme->bg->pix); - XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); - } - -@@ -294,10 +319,10 @@ drw_text(Drw *drw, int x, int y, unsigne - for(i = len; i && i > len - 3; buf[--i] = '.'); - - if (render) { -- th = curfont->ascent + curfont->descent; -- ty = y + (h / 2) - (th / 2) + curfont->ascent; -+ th = pad ? (curfont->ascent + curfont->descent) : 0; -+ ty = y + ((h + curfont->ascent - curfont->descent) / 2); - tx = x + (h / 2); -- XftDrawStringUtf8(d, invert ? &drw->scheme->bg->rgb : &drw->scheme->fg->rgb, curfont->xfont, tx, ty, (XftChar8 *)buf, len); -+ XftDrawStringUtf8(d, &drw->scheme->fg->rgb, curfont->xfont, tx, ty, (XftChar8 *)buf, len); - } - - x += tex.w; -diff -up dwm/drw.h dwm_git_colors/drw.h ---- dwm/drw.h 2015-03-24 10:00:33.865796838 -0700 -+++ dwm_git_colors/drw.h 2015-03-24 09:22:03.216317586 -0700 -@@ -67,8 +67,9 @@ void drw_setfont(Drw *drw, Fnt *font); - void drw_setscheme(Drw *drw, ClrScheme *scheme); + drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert) + { +diff -up dwm/drw.h dwm-statuscolors/drw.h +--- dwm/drw.h 2015-11-08 15:39:37.000000000 -0700 ++++ dwm-statuscolors/drw.h 2015-11-28 15:39:44.427726312 -0700 +@@ -67,6 +67,8 @@ void drw_setfont(Drw *, Fnt *); + void drw_setscheme(Drw *, ClrScheme *); /* Drawing functions */ --void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert); --int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int invert); -+int drw_colored_text(Drw *drw, ClrScheme *scheme, int numcolors, int x, int y, unsigned int w, unsigned int h, char *text); -+void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty); -+int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int pad); ++int drw_get_width(Drw *, int, const char *); ++void drw_colored_text(Drw *, ClrScheme *, int, int, int, unsigned int, unsigned int, char *); + void drw_rect(Drw *, int, int, unsigned int, unsigned int, int, int, int); + int drw_text(Drw *, int, int, unsigned int, unsigned int, const char *, int); - /* Map functions */ - void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); -Binary files dwm/drw.o and dwm_git_colors/drw.o differ -Binary files dwm/dwm and dwm_git_colors/dwm differ -diff -up dwm/dwm.c dwm_git_colors/dwm.c ---- dwm/dwm.c 2015-03-24 10:02:59.752217939 -0700 -+++ dwm_git_colors/dwm.c 2015-03-24 09:23:22.826334134 -0700 +diff -up dwm/dwm.c dwm-statuscolors/dwm.c +--- dwm/dwm.c 2015-11-08 15:39:37.000000000 -0700 ++++ dwm-statuscolors/dwm.c 2015-11-28 15:45:32.134406853 -0700 @@ -51,6 +51,7 @@ * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) @@ -103,26 +93,26 @@ diff -up dwm/dwm.c dwm_git_colors/dwm.c #define MOUSEMASK (BUTTONMASK|PointerMotionMask) #define WIDTH(X) ((X)->w + 2 * (X)->bw) #define HEIGHT(X) ((X)->h + 2 * (X)->bw) -@@ -261,7 +263,7 @@ static void (*handler[LASTEvent]) (XEven +@@ -261,7 +262,7 @@ static void (*handler[LASTEvent]) (XEven static Atom wmatom[WMLast], netatom[NetLast]; - static Bool running = True; + static int running = 1; static Cur *cursor[CurLast]; -static ClrScheme scheme[SchemeLast]; +static ClrScheme scheme[MAXCOLORS]; static Display *dpy; static Drw *drw; static Monitor *mons, *selmon; -@@ -703,14 +716,14 @@ drawbar(Monitor *m) { +@@ -718,35 +719,35 @@ drawbar(Monitor *m) x = 0; - for(i = 0; i < LENGTH(tags); i++) { + for (i = 0; i < LENGTH(tags); i++) { w = TEXTW(tags[i]); - drw_setscheme(drw, m->tagset[m->seltags] & 1 << i ? &scheme[SchemeSel] : &scheme[SchemeNorm]); - drw_text(drw, x, 0, w, bh, tags[i], urg & 1 << i); -+ drw_setscheme(drw, &scheme[(m->tagset[m->seltags] & 1 << i) ? 1 : (urg & 1 << i ? 2:0)]); -+ drw_text(drw, x, 0, w, bh, tags[i], 1); - drw_rect(drw, x, 0, w, bh, m == selmon && selmon->sel && selmon->sel->tags & 1 << i, ++ drw_setscheme(drw, &scheme[(m->tagset[m->seltags] & 1 << i) ? 1 : (urg & 1 << i ? 2 : 0)]); ++ drw_text(drw, x, 0, w, bh, tags[i], 0); + drw_rect(drw, x + 1, 1, dx, dx, m == selmon && selmon->sel && selmon->sel->tags & 1 << i, - occ & 1 << i, urg & 1 << i); -+ occ & 1 << i); ++ occ & 1 << i, 0); x += w; } w = blw = TEXTW(m->ltsymbol); @@ -131,41 +121,41 @@ diff -up dwm/dwm.c dwm_git_colors/dwm.c drw_text(drw, x, 0, w, bh, m->ltsymbol, 0); x += w; xx = x; -@@ -721,19 +734,19 @@ drawbar(Monitor *m) { + if (m == selmon) { /* status is only drawn on selected monitor */ +- w = TEXTW(stext); ++ w = drw_get_width(drw, NUMCOLORS, stext); + x = m->ww - w; + if (x < xx) { x = xx; w = m->ww - xx; } - drw_text(drw, x, 0, w, bh, stext, 0); + drw_colored_text(drw, scheme, NUMCOLORS, x, 0, w, bh, stext); - } - else + } else x = m->ww; - if((w = x - xx) > bh) { + if ((w = x - xx) > bh) { x = xx; - if(m->sel) { + if (m->sel) { - drw_setscheme(drw, m == selmon ? &scheme[SchemeSel] : &scheme[SchemeNorm]); -- drw_text(drw, x, 0, w, bh, m->sel->name, 0); -- drw_rect(drw, x, 0, w, bh, m->sel->isfixed, m->sel->isfloating, 0); + drw_setscheme(drw, &scheme[m == selmon ? 1 : 0]); -+ drw_text(drw, x, 0, w, bh, m->sel->name, 1); -+ drw_rect(drw, x, 0, w, bh, m->sel->isfixed, m->sel->isfloating); - } - else { + drw_text(drw, x, 0, w, bh, m->sel->name, 0); + drw_rect(drw, x + 1, 1, dx, dx, m->sel->isfixed, m->sel->isfloating, 0); + } else { - drw_setscheme(drw, &scheme[SchemeNorm]); + drw_setscheme(drw, &scheme[0]); - drw_text(drw, x, 0, w, bh, NULL, 0); + drw_rect(drw, x, 0, w, bh, 1, 0, 1); } } -@@ -791,7 +804,7 @@ focus(Client *c) { +@@ -807,7 +808,7 @@ focus(Client *c) detachstack(c); attachstack(c); - grabbuttons(c, True); + grabbuttons(c, 1); - XSetWindowBorder(dpy, c->win, scheme[SchemeSel].border->pix); + XSetWindowBorder(dpy, c->win, scheme[1].border->pix); setfocus(c); - } - else { -@@ -1039,7 +1052,7 @@ manage(Window w, XWindowAttributes *wa) + } else { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); +@@ -1065,7 +1066,7 @@ manage(Window w, XWindowAttributes *wa) wc.border_width = c->bw; XConfigureWindow(dpy, w, CWBorderWidth, &wc); @@ -174,7 +164,7 @@ diff -up dwm/dwm.c dwm_git_colors/dwm.c configure(c); /* propagates border_width, if size doesn't change */ updatewindowtype(c); updatesizehints(c); -@@ -1531,12 +1544,12 @@ setup(void) { +@@ -1580,12 +1581,12 @@ setup(void) cursor[CurResize] = drw_cur_create(drw, XC_sizing); cursor[CurMove] = drw_cur_create(drw, XC_fleur); /* init appearance */ @@ -193,14 +183,12 @@ diff -up dwm/dwm.c dwm_git_colors/dwm.c /* init bars */ updatebars(); updatestatus(); -@@ -1685,7 +1698,7 @@ unfocus(Client *c, Bool setfocus) { - if(!c) +@@ -1745,7 +1746,7 @@ unfocus(Client *c, int setfocus) + if (!c) return; - grabbuttons(c, False); + grabbuttons(c, 0); - XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].border->pix); + XSetWindowBorder(dpy, c->win, scheme[0].border->pix); - if(setfocus) { + if (setfocus) { XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); XDeleteProperty(dpy, root, netatom[NetActiveWindow]); -Binary files dwm/dwm.o and dwm_git_colors/dwm.o differ -Common subdirectories: dwm/.git and dwm_git_colors/.git diff --git a/dwm.suckless.org/patches/dwm-6.1-swallowing.diff b/dwm.suckless.org/patches/dwm-6.1-swallowing.diff @@ -0,0 +1,377 @@ +diff --git a/config.def.h b/config.def.h +index 7054c06..d1140ff 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -24,9 +24,10 @@ static const Rule rules[] = { + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ +- /* class instance title tags mask isfloating monitor */ +- { "Gimp", NULL, NULL, 0, 1, -1 }, +- { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, ++ /* class instance title tags mask isfloating isterminal noswallow monitor */ ++ { "Gimp", NULL, NULL, 0, 1, 0, 0, -1 }, ++ { "Firefox", NULL, NULL, 1 << 8, 0, 0, 0, -1 }, ++ { "st-", NULL, NULL, 0, 0, 1, 1, -1 }, + }; + + /* layout(s) */ +diff --git a/dwm.c b/dwm.c +index ff7e096..b50436a 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -40,6 +40,10 @@ + #include <X11/extensions/Xinerama.h> + #endif /* XINERAMA */ + #include <X11/Xft/Xft.h> ++#ifdef SWALLOWING ++#include <X11/Xlib-xcb.h> ++#include <xcb/res.h> ++#endif + + #include "drw.h" + #include "util.h" +@@ -92,9 +96,11 @@ struct Client { + int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int bw, oldbw; + unsigned int tags; +- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; ++ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow; ++ pid_t pid; + Client *next; + Client *snext; ++ Client *swallowing; + Monitor *mon; + Window win; + }; +@@ -138,6 +144,8 @@ typedef struct { + const char *title; + unsigned int tags; + int isfloating; ++ int isterminal; ++ int noswallow; + int monitor; + } Rule; + +@@ -170,12 +178,14 @@ static void focus(Client *c); + static void focusin(XEvent *e); + static void focusmon(const Arg *arg); + static void focusstack(const Arg *arg); ++static pid_t getparentprocess(pid_t p); + static int getrootptr(int *x, int *y); + static long getstate(Window w); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); + static void grabbuttons(Client *c, int focused); + static void grabkeys(void); + static void incnmaster(const Arg *arg); ++static int isdescprocess(pid_t p, pid_t c); + static void keypress(XEvent *e); + static void killclient(const Arg *arg); + static void manage(Window w, XWindowAttributes *wa); +@@ -206,8 +216,10 @@ static void setup(void); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static Client *swallowingclient(Window w); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); ++static Client *termforwin(const Client *c); + static void tile(Monitor *); + static void togglebar(const Arg *arg); + static void togglefloating(const Arg *arg); +@@ -227,6 +239,7 @@ static void updatewindowtype(Client *c); + static void updatetitle(Client *c); + static void updatewmhints(Client *c); + static void view(const Arg *arg); ++static pid_t winpid(Window w); + static Client *wintoclient(Window w); + static Monitor *wintomon(Window w); + static int xerror(Display *dpy, XErrorEvent *ee); +@@ -267,6 +280,10 @@ static Drw *drw; + static Monitor *mons, *selmon; + static Window root; + ++#ifdef SWALLOWING ++static xcb_connection_t *xcon; ++#endif /* SWALLOWING */ ++ + /* configuration, allows nested code to access above variables */ + #include "config.h" + +@@ -296,6 +313,7 @@ applyrules(Client *c) + && (!r->class || strstr(class, r->class)) + && (!r->instance || strstr(instance, r->instance))) + { ++ c->isterminal = r->isterminal; + c->isfloating = r->isfloating; + c->tags |= r->tags; + for (m = mons; m && m->num != r->monitor; m = m->next); +@@ -413,6 +431,46 @@ attachstack(Client *c) + } + + void ++swallow(Client *p, Client *c) ++{ ++ if (c->noswallow || c->isterminal) ++ return; ++ ++ detach(c); ++ detachstack(c); ++ ++ setclientstate(c, WithdrawnState); ++ XUnmapWindow(dpy, p->win); ++ ++ p->swallowing = c; ++ c->mon = p->mon; ++ ++ Window w = p->win; ++ p->win = c->win; ++ c->win = w; ++ updatetitle(p); ++ arrange(p->mon); ++ configure(p); ++ updateclientlist(); ++} ++ ++void ++unswallow(Client *c) ++{ ++ c->win = c->swallowing->win; ++ ++ free(c->swallowing); ++ c->swallowing = NULL; ++ ++ updatetitle(c); ++ arrange(c->mon); ++ XMapWindow(dpy, c->win); ++ XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); ++ configure(c); ++ setclientstate(c, NormalState); ++} ++ ++void + buttonpress(XEvent *e) + { + unsigned int i, x, click; +@@ -475,7 +533,7 @@ cleanup(void) + selmon->lt[selmon->sellt] = &foo; + for (m = mons; m; m = m->next) + while (m->stack) +- unmanage(m->stack, 0); ++ unmanage(m->stack, 0); // XXX - unmanage swallowing windows too + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); +@@ -666,6 +724,9 @@ destroynotify(XEvent *e) + + if ((c = wintoclient(ev->window))) + unmanage(c, 1); ++ ++ else if ((c = swallowingclient(ev->window))) ++ unmanage(c->swallowing, 1); + } + + void +@@ -1037,12 +1098,13 @@ killclient(const Arg *arg) + void + manage(Window w, XWindowAttributes *wa) + { +- Client *c, *t = NULL; ++ Client *c, *t, *term = NULL; + Window trans = None; + XWindowChanges wc; + + c = ecalloc(1, sizeof(Client)); + c->win = w; ++ c->pid = winpid(w); + updatetitle(c); + if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { + c->mon = t->mon; +@@ -1050,7 +1112,9 @@ manage(Window w, XWindowAttributes *wa) + } else { + c->mon = selmon; + applyrules(c); ++ term = termforwin(c); + } ++ + /* geometry */ + c->x = c->oldx = wa->x; + c->y = c->oldy = wa->y; +@@ -1092,6 +1156,8 @@ manage(Window w, XWindowAttributes *wa) + c->mon->sel = c; + arrange(c->mon); + XMapWindow(dpy, c->win); ++ if (term) ++ swallow(term, c); + focus(NULL); + } + +@@ -1763,6 +1829,20 @@ unmanage(Client *c, int destroyed) + Monitor *m = c->mon; + XWindowChanges wc; + ++ if (c->swallowing) { ++ unswallow(c); ++ return; ++ } ++ ++ Client *s = swallowingclient(c->win); ++ if (s) { ++ free(s->swallowing); ++ s->swallowing = NULL; ++ arrange(m); ++ focus(NULL); ++ return; ++ } ++ + /* The server grab construct avoids race conditions. */ + detach(c); + detachstack(c); +@@ -1778,9 +1858,12 @@ unmanage(Client *c, int destroyed) + XUngrabServer(dpy); + } + free(c); +- focus(NULL); +- updateclientlist(); +- arrange(m); ++ ++ if (!s) { ++ arrange(m); ++ focus(NULL); ++ updateclientlist(); ++ } + } + + void +@@ -2045,16 +2128,118 @@ view(const Arg *arg) + arrange(selmon); + } + ++pid_t ++winpid(Window w) ++{ ++ pid_t result = 0; ++ ++#ifdef SWALLOWING ++ xcb_res_client_id_spec_t spec = {0}; ++ spec.client = w; ++ spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID; ++ ++ xcb_generic_error_t *e = NULL; ++ xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec); ++ xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e); ++ ++ if (!r) ++ return (pid_t)0; ++ ++ xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r); ++ for (; i.rem; xcb_res_client_id_value_next(&i)) { ++ spec = i.data->spec; ++ if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) { ++ uint32_t *t = xcb_res_client_id_value_value(i.data); ++ result = *t; ++ break; ++ } ++ } ++ ++ free(r); ++#endif /* SWALLOWING */ ++ ++ if (result == (pid_t)-1) ++ result = 0; ++ return result; ++} ++ ++pid_t ++getparentprocess(pid_t p) ++{ ++ unsigned int v = 0; ++ ++#ifdef __linux__ ++ FILE *f; ++ char buf[256]; ++ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); ++ ++ if (!(f = fopen(buf, "r"))) ++ return 0; ++ ++ fscanf(f, "%*u %*s %*c %u", &v); ++ fclose(f); ++#endif /* __linux__ */ ++ ++ return (pid_t)v; ++} ++ ++int ++isdescprocess(pid_t p, pid_t c) ++{ ++ while (p != c && c != 0) ++ c = getparentprocess(c); ++ ++ return (int)c; ++} ++ ++Client * ++termforwin(const Client *w) ++{ ++ Client *c; ++ Monitor *m; ++ ++ if (!w->pid || w->isterminal) ++ return NULL; ++ ++ for (m = mons; m; m = m->next) { ++ for (c = m->clients; c; c = c->next) { ++ if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) ++ return c; ++ } ++ } ++ ++ return NULL; ++} ++ ++Client * ++swallowingclient(Window w) ++{ ++ Client *c; ++ Monitor *m; ++ ++ for (m = mons; m; m = m->next) { ++ for (c = m->clients; c; c = c->next) { ++ if (c->swallowing && c->swallowing->win == w) ++ return c; ++ } ++ } ++ ++ return NULL; ++} ++ + Client * + wintoclient(Window w) + { + Client *c; + Monitor *m; + +- for (m = mons; m; m = m->next) +- for (c = m->clients; c; c = c->next) ++ for (m = mons; m; m = m->next) { ++ for (c = m->clients; c; c = c->next) { + if (c->win == w) + return c; ++ } ++ } ++ + return NULL; + } + +@@ -2136,6 +2321,10 @@ main(int argc, char *argv[]) + fputs("warning: no locale support\n", stderr); + if (!(dpy = XOpenDisplay(NULL))) + die("dwm: cannot open display\n"); ++#ifdef SWALLOWING ++ if (!(xcon = XGetXCBConnection(dpy))) ++ die("dwm: cannot get xcb connection\n"); ++#endif + checkotherwm(); + setup(); + scan(); diff --git a/dwm.suckless.org/patches/dwm-6.1-systray.diff b/dwm.suckless.org/patches/dwm-6.1-systray.diff @@ -1,33 +1,25 @@ -Author: Jan Christoph Ebersbach <jceb@e-jc.de>, inspired by http://code.google.com/p/dwm-plus -URL: http://dwm.suckless.org/patches/systray -Implements a system tray for dwm. - -Contributors: -- Carlos Pita, thanks for investigating multi monitor issues and sending in a - patch - -Index: dwm/config.def.h -=================================================================== ---- dwm/config.def.h.orig -+++ dwm/config.def.h -@@ -10,6 +10,10 @@ static const char selbgcolor[] = "# +diff --git a/config.def.h b/config.def.h +index 7054c06..8393a58 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -13,6 +13,10 @@ static const char selbgcolor[] = "#005577"; static const char selfgcolor[] = "#eeeeee"; static const unsigned int borderpx = 1; /* border pixel of windows */ static const unsigned int snap = 32; /* snap pixel */ +static const 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 Bool systraypinningfailfirst = True; /* True: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ -+static const Bool showsystray = True; /* False means no systray */ - static const Bool showbar = True; /* False means no bar */ - static const Bool topbar = True; /* False means bottom bar */ ++static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, 0: 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 */ -Index: dwm/dwm.c -=================================================================== ---- dwm/dwm.c.orig -+++ dwm/dwm.c -@@ -56,12 +56,30 @@ +diff --git a/dwm.c b/dwm.c +index 0362114..e574573 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -57,12 +57,30 @@ #define TAGMASK ((1 << LENGTH(tags)) - 1) - #define TEXTW(X) (drw_font_getexts_width(drw->font, X, strlen(X)) + drw->font->h) + #define TEXTW(X) (drw_text(drw, 0, 0, 0, 0, (X), 0) + drw->fonts[0]->h) +#define SYSTEM_TRAY_REQUEST_DOCK 0 +#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0 @@ -59,7 +51,7 @@ Index: dwm/dwm.c enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ -@@ -140,6 +158,12 @@ typedef struct { +@@ -141,6 +159,12 @@ typedef struct { int monitor; } Rule; @@ -71,24 +63,24 @@ Index: dwm/dwm.c + /* function declarations */ static void applyrules(Client *c); - static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact); -@@ -169,8 +193,10 @@ static void focus(Client *c); + static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); +@@ -170,8 +194,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 Bool getrootptr(int *x, int *y); + static int getrootptr(int *x, int *y); static long getstate(Window w); +static unsigned int getsystraywidth(); - static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); - static void grabbuttons(Client *c, Bool focused); + 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 *); +@@ -189,13 +215,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, Bool interact); + 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); @@ -96,12 +88,12 @@ Index: dwm/dwm.c static void restack(Monitor *m); static void run(void); static void scan(void); --static Bool sendevent(Client *c, Atom proto); -+static Bool sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); +-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); -@@ -205,6 +234,7 @@ static void setup(void); +@@ -206,6 +235,7 @@ static void setup(void); static void showhide(Client *c); static void sigchld(int unused); static void spawn(const Arg *arg); @@ -109,7 +101,7 @@ Index: dwm/dwm.c static void tag(const Arg *arg); static void tagmon(const Arg *arg); static void tile(Monitor *); -@@ -222,18 +252,24 @@ static void updateclientlist(void); +@@ -223,18 +253,24 @@ static void updateclientlist(void); static void updatenumlockmask(void); static void updatesizehints(Client *c); static void updatestatus(void); @@ -134,7 +126,7 @@ Index: dwm/dwm.c static const char broken[] = "broken"; static char stext[256]; static int screen; -@@ -255,9 +291,10 @@ static void (*handler[LASTEvent]) (XEven +@@ -256,9 +292,10 @@ static void (*handler[LASTEvent]) (XEvent *) = { [MapRequest] = maprequest, [MotionNotify] = motionnotify, [PropertyNotify] = propertynotify, @@ -143,34 +135,34 @@ Index: dwm/dwm.c }; -static Atom wmatom[WMLast], netatom[NetLast]; +static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; - static Bool running = True; + static int running = 1; static Cur *cursor[CurLast]; static ClrScheme scheme[SchemeLast]; -@@ -471,6 +508,11 @@ cleanup(void) { +@@ -479,6 +516,11 @@ cleanup(void) XUngrabKey(dpy, AnyKey, AnyModifier, root); - while(mons) + while (mons) cleanupmon(mons); -+ if(showsystray) { ++ if (showsystray) { + XUnmapWindow(dpy, systray->win); + XDestroyWindow(dpy, systray->win); + free(systray); + } - drw_cur_free(drw, cursor[CurNormal]); - drw_cur_free(drw, cursor[CurResize]); - drw_cur_free(drw, cursor[CurMove]); -@@ -516,9 +558,49 @@ clearurgent(Client *c) { - + for (i = 0; i < CurLast; i++) + drw_cur_free(drw, cursor[i]); + for (i = 0; i < SchemeLast; i++) { +@@ -524,9 +566,50 @@ clearurgent(Client *c) void - clientmessage(XEvent *e) { + 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]) { ++ 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)))) ++ 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)); + c->win = cme->data.l[2]; + c->mon = selmon; @@ -191,7 +183,7 @@ Index: dwm/dwm.c + XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); + XReparentWindow(dpy, c->win, systray->win, 0, 0); + /* use parents background color */ -+ swa.background_pixel = scheme[SchemeNorm].bg->rgb; ++ swa.background_pixel = scheme[SchemeNorm].bg->pix; + 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 */ @@ -205,23 +197,24 @@ Index: dwm/dwm.c + } + return; + } - if(!c) ++ + if (!c) return; - if(cme->message_type == netatom[NetWMState]) { -@@ -568,7 +650,7 @@ configurenotify(XEvent *e) { + if (cme->message_type == netatom[NetWMState]) { +@@ -577,7 +660,7 @@ configurenotify(XEvent *e) drw_resize(drw, sw, bh); updatebars(); - for(m = mons; m; m = m->next) + for (m = mons; m; m = m->next) - XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); + resizebarwin(m); focus(NULL); arrange(NULL); } -@@ -652,6 +734,11 @@ destroynotify(XEvent *e) { +@@ -661,6 +744,11 @@ destroynotify(XEvent *e) - if((c = wintoclient(ev->window))) - unmanage(c, True); -+ else if((c = wintosystrayicon(ev->window))) { + if ((c = wintoclient(ev->window))) + unmanage(c, 1); ++ else if ((c = wintosystrayicon(ev->window))) { + removesystrayicon(c); + resizebarwin(selmon); + updatesystray(); @@ -229,65 +222,65 @@ Index: dwm/dwm.c } void -@@ -696,6 +783,7 @@ drawbar(Monitor *m) { - unsigned int i, occ = 0, urg = 0; - Client *c; +@@ -710,6 +798,7 @@ drawbar(Monitor *m) + + dx = (drw->fonts[0]->ascent + drw->fonts[0]->descent + 2) / 4; + resizebarwin(m); - for(c = m->clients; c; c = c->next) { + for (c = m->clients; c; c = c->next) { occ |= c->tags; - if(c->isurgent) -@@ -718,6 +806,9 @@ drawbar(Monitor *m) { - if(m == selmon) { /* status is only drawn on selected monitor */ + if (c->isurgent) +@@ -732,6 +821,9 @@ drawbar(Monitor *m) + if (m == selmon) { /* status is only drawn on selected monitor */ w = TEXTW(stext); x = m->ww - w; -+ if(showsystray && m == systraytomon(m)) { ++ if (showsystray && m == systraytomon(m)) { + x -= getsystraywidth(); + } - if(x < xx) { + if (x < xx) { x = xx; w = m->ww - xx; -@@ -747,6 +838,7 @@ drawbars(void) { +@@ -760,6 +852,7 @@ drawbars(void) - for(m = mons; m; m = m->next) + for (m = mons; m; m = m->next) drawbar(m); + updatesystray(); } void -@@ -773,8 +865,11 @@ expose(XEvent *e) { +@@ -787,8 +880,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))) { +- if (ev->count == 0 && (m = wintomon(ev->window))) ++ if (ev->count == 0 && (m = wintomon(ev->window))) { drawbar(m); -+ if(m == selmon) ++ if (m == selmon) + updatesystray(); + } } void -@@ -857,10 +952,17 @@ getatomprop(Client *c, Atom prop) { +@@ -875,10 +971,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]) ++ 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, +- 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) ++ if (da == xatom[XembedInfo] && dl == 2) + atom = ((Atom *)p)[1]; XFree(p); } return atom; -@@ -892,6 +994,15 @@ getstate(Window w) { +@@ -912,6 +1015,15 @@ getstate(Window w) return result; } @@ -295,42 +288,42 @@ Index: dwm/dwm.c +getsystraywidth() { + unsigned int w = 0; + Client *i; -+ if(showsystray) -+ for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ; ++ if (showsystray) ++ for (i = systray->icons; i; w += i->w + systrayspacing, i = i->next); + return w ? w + systrayspacing : 1; +} + - Bool - gettextprop(Window w, Atom atom, char *text, unsigned int size) { - char **list = NULL; -@@ -992,7 +1103,7 @@ void - killclient(const Arg *arg) { - if(!selmon->sel) + int + gettextprop(Window w, Atom atom, char *text, unsigned int size) + { +@@ -1018,7 +1130,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)) { +- 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); -@@ -1078,6 +1189,12 @@ void - maprequest(XEvent *e) { +@@ -1105,6 +1217,12 @@ maprequest(XEvent *e) + { static XWindowAttributes wa; XMapRequestEvent *ev = &e->xmaprequest; + Client *i; -+ if((i = wintosystrayicon(ev->window))) { ++ 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)) + if (!XGetWindowAttributes(dpy, ev->window, &wa)) return; -@@ -1194,6 +1311,16 @@ propertynotify(XEvent *e) { +@@ -1232,6 +1350,16 @@ propertynotify(XEvent *e) Window trans; XPropertyEvent *ev = &e->xproperty; -+ if((c = wintosystrayicon(ev->window))) { -+ if(ev->atom == XA_WM_NORMAL_HINTS) { ++ if ((c = wintosystrayicon(ev->window))) { ++ if (ev->atom == XA_WM_NORMAL_HINTS) { + updatesizehints(c); + updatesystrayicongeom(c, c->w, c->h); + } @@ -339,44 +332,45 @@ Index: dwm/dwm.c + resizebarwin(selmon); + updatesystray(); + } - if((ev->window == root) && (ev->atom == XA_WM_NAME)) + if ((ev->window == root) && (ev->atom == XA_WM_NAME)) updatestatus(); - else if(ev->state == PropertyDelete) -@@ -1243,12 +1370,33 @@ recttomon(int x, int y, int w, int h) { + else if (ev->state == PropertyDelete) +@@ -1283,6 +1411,19 @@ recttomon(int x, int y, int w, int h) } void +removesystrayicon(Client *i) { + Client **ii; + -+ if(!showsystray || !i) ++ if (!showsystray || !i) + return; -+ for(ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); -+ if(ii) ++ 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, Bool interact) { - if(applysizehints(c, &x, &y, &w, &h, interact)) - resizeclient(c, x, y, w, h); + resize(Client *c, int x, int y, int w, int h, int interact) + { + if (applysizehints(c, &x, &y, &w, &h, interact)) +@@ -1290,6 +1431,14 @@ resize(Client *c, int x, int y, int w, int h, int interact) } void +resizebarwin(Monitor *m) { + unsigned int w = m->ww; -+ if(showsystray && m == systraytomon(m)) ++ 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) { + resizeclient(Client *c, int x, int y, int w, int h) + { XWindowChanges wc; - -@@ -1315,6 +1463,18 @@ resizemouse(const Arg *arg) { +@@ -1362,6 +1511,18 @@ resizemouse(const Arg *arg) } void @@ -384,7 +378,7 @@ Index: dwm/dwm.c + XResizeRequestEvent *ev = &e->xresizerequest; + Client *i; + -+ if((i = wintosystrayicon(ev->window))) { ++ if ((i = wintosystrayicon(ev->window))) { + updatesystrayicongeom(i, ev->width, ev->height); + resizebarwin(selmon); + updatesystray(); @@ -392,28 +386,29 @@ Index: dwm/dwm.c +} + +void - restack(Monitor *m) { + restack(Monitor *m) + { Client *c; - XEvent ev; -@@ -1398,25 +1558,35 @@ setclientstate(Client *c, long state) { +@@ -1450,26 +1611,36 @@ setclientstate(Client *c, long state) } - Bool --sendevent(Client *c, Atom proto) { -+sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) { + 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; - Bool exists = False; + int exists = 0; XEvent ev; -- if(XGetWMProtocols(dpy, c->win, &protocols, &n)) { -- while(!exists && n--) +- if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { +- while (!exists && n--) - exists = protocols[n] == proto; - XFree(protocols); -+ if(proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { ++ if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { + mt = wmatom[WMProtocols]; -+ if(XGetWMProtocols(dpy, w, &protocols, &n)) { ++ if (XGetWMProtocols(dpy, w, &protocols, &n)) { + while(!exists && n--) + exists = protocols[n] == proto; + XFree(protocols); @@ -423,7 +418,7 @@ Index: dwm/dwm.c + exists = True; + mt = proto; } - if(exists) { + if (exists) { ev.type = ClientMessage; - ev.xclient.window = c->win; - ev.xclient.message_type = wmatom[WMProtocols]; @@ -442,16 +437,16 @@ Index: dwm/dwm.c } return exists; } -@@ -1429,7 +1599,7 @@ setfocus(Client *c) { - XA_WINDOW, 32, PropModeReplace, - (unsigned char *) &(c->win), 1); +@@ -1483,7 +1654,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 -@@ -1511,12 +1681,18 @@ setup(void) { +@@ -1569,12 +1740,18 @@ 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); @@ -470,7 +465,7 @@ Index: dwm/dwm.c /* init cursors */ cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); cursor[CurResize] = drw_cur_create(drw, XC_sizing); -@@ -1528,6 +1704,8 @@ setup(void) { +@@ -1586,6 +1763,8 @@ setup(void) scheme[SchemeSel].border = drw_clr_create(drw, selbordercolor); scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor); scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor); @@ -479,7 +474,7 @@ Index: dwm/dwm.c /* init bars */ updatebars(); updatestatus(); -@@ -1583,6 +1761,22 @@ spawn(const Arg *arg) { +@@ -1645,6 +1824,22 @@ spawn(const Arg *arg) } } @@ -487,34 +482,34 @@ Index: dwm/dwm.c +systraytomon(Monitor *m) { + Monitor *t; + int i, n; -+ if(!systraypinning) { -+ if(!m) ++ 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) ++ 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 - tag(const Arg *arg) { - if(selmon->sel && arg->ui & TAGMASK) { -@@ -1629,7 +1823,18 @@ void - togglebar(const Arg *arg) { + tag(const Arg *arg) + { +@@ -1694,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) { ++ if (showsystray) { + XWindowChanges wc; -+ if(!selmon->showbar) ++ if (!selmon->showbar) + wc.y = -bh; -+ else if(selmon->showbar) { ++ else if (selmon->showbar) { + wc.y = 0; -+ if(!selmon->topbar) ++ if (!selmon->topbar) + wc.y = selmon->mh - bh; + } + XConfigureWindow(dpy, systray->win, CWY, &wc); @@ -522,11 +517,11 @@ Index: dwm/dwm.c arrange(selmon); } -@@ -1719,11 +1924,18 @@ unmapnotify(XEvent *e) { +@@ -1790,11 +1996,17 @@ unmapnotify(XEvent *e) else - unmanage(c, False); + unmanage(c, 0); } -+ else if((c = wintosystrayicon(ev->window))) { ++ else if ((c = wintosystrayicon(ev->window))) { + removesystrayicon(c); + resizebarwin(selmon); + updatesystray(); @@ -534,47 +529,46 @@ Index: dwm/dwm.c } void - updatebars(void) { + updatebars(void) + { + unsigned int w; Monitor *m; -+ XSetWindowAttributes wa = { .override_redirect = True, - .background_pixmap = ParentRelative, -@@ -1732,10 +1944,15 @@ updatebars(void) { - for(m = mons; m; m = m->next) { +@@ -1804,10 +2016,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)) ++ 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)) ++ if (showsystray && m == systraytomon(m)) + XMapRaised(dpy, systray->win); XMapRaised(dpy, m->barwin); } } -@@ -1929,6 +2146,117 @@ updatestatus(void) { +@@ -1998,6 +2215,117 @@ updatestatus(void) } void +updatesystrayicongeom(Client *i, int w, int h) { -+ if(i) { ++ if (i) { + i->h = bh; -+ if(w == h) ++ if (w == h) + i->w = bh; -+ else if(h == 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 dimenons if they don't want to */ -+ if(i->h > bh) { -+ if(i->w == i->h) ++ if (i->h > bh) { ++ if (i->w == i->h) + i->w = bh; + else + i->w = (int) ((float)bh * ((float)i->w / (float)i->h)); @@ -588,17 +582,17 @@ Index: dwm/dwm.c + long flags; + int code = 0; + -+ if(!showsystray || !i || ev->atom != xatom[XembedInfo] || ++ if (!showsystray || !i || ev->atom != xatom[XembedInfo] || + !(flags = getatomprop(i, xatom[XembedInfo]))) + return; + -+ if(flags & XEMBED_MAPPED && !i->tags) { ++ 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) { ++ else if (!(flags & XEMBED_MAPPED) && i->tags) { + i->tags = 0; + code = XEMBED_WINDOW_DEACTIVATE; + XUnmapWindow(dpy, i->win); @@ -619,23 +613,23 @@ Index: dwm/dwm.c + unsigned int x = m->mx + m->mw; + unsigned int w = 1; + -+ if(!showsystray) ++ if (!showsystray) + return; -+ if(!systray) { ++ if (!systray) { + /* init systray */ -+ if(!(systray = (Systray *)calloc(1, sizeof(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].bg->rgb); ++ systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel].bg->pix); + wa.event_mask = ButtonPressMask | ExposureMask; + wa.override_redirect = True; -+ wa.background_pixel = scheme[SchemeNorm].bg->rgb; ++ wa.background_pixel = scheme[SchemeNorm].bg->pix; + XSelectInput(dpy, systray->win, SubstructureNotifyMask); + XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, + PropModeReplace, (unsigned char *)&systrayorientation, 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) { ++ if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { + sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0); + XSync(dpy, False); + } @@ -646,16 +640,16 @@ Index: dwm/dwm.c + return; + } + } -+ for(w = 0, i = systray->icons; i; i = i->next) { ++ for (w = 0, i = systray->icons; i; i = i->next) { + /* make sure the background color stays the same */ -+ wa.background_pixel = scheme[SchemeNorm].bg->rgb; ++ wa.background_pixel = scheme[SchemeNorm].bg->pix; + 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) ++ if (i->mon != m) + i->mon = m; + } + w = w ? w + systrayspacing : 1; @@ -667,16 +661,16 @@ Index: dwm/dwm.c + XMapWindow(dpy, systray->win); + XMapSubwindows(dpy, systray->win); + /* redraw background */ -+ XSetForeground(dpy, drw->gc, scheme[SchemeNorm].bg->rgb); ++ XSetForeground(dpy, drw->gc, scheme[SchemeNorm].bg->pix); + XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); + XSync(dpy, False); +} + +void - updatewindowtype(Client *c) { + updatewindowtype(Client *c) + { Atom state = getatomprop(c, netatom[NetWMState]); - Atom wtype = getatomprop(c, netatom[NetWMWindowType]); -@@ -1997,6 +2325,16 @@ wintomon(Window w) { +@@ -2070,6 +2398,16 @@ wintomon(Window w) return selmon; } @@ -684,9 +678,9 @@ Index: dwm/dwm.c +wintosystrayicon(Window w) { + Client *i = NULL; + -+ if(!showsystray || !w) ++ if (!showsystray || !w) + return i; -+ for(i = systray->icons; i && i->win != w; i = i->next) ; ++ for (i = systray->icons; i && i->win != w; i = i->next); + return i; +} + diff --git a/dwm.suckless.org/patches/dwm-6.1-tab-v2b.diff b/dwm.suckless.org/patches/dwm-6.1-tab-v2b.diff @@ -0,0 +1,511 @@ +diff --git a/config.def.h b/config.def.h +index 7054c06..e784231 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -15,6 +15,12 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ ++/* Display modes of the tab bar: never shown, always shown, shown only in */ ++/* monocle mode in presence of several windows. */ ++/* Modes after showtab_nmodes are disabled */ ++enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always}; ++static const int showtab = showtab_auto; /* Default tab bar show mode */ ++static const int toptab = False; /* False means bottom tab bar */ + + /* tagging */ + static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; +@@ -62,6 +68,7 @@ static Key keys[] = { + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, + { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_b, togglebar, {0} }, ++ { MODKEY, XK_w, tabmode, {-1} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, +@@ -109,5 +116,6 @@ static Button buttons[] = { + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, ++ { ClkTabBar, 0, Button1, focuswin, {0} }, + }; + +diff --git a/dwm.1 b/dwm.1 +index 6687011..9ff827c 100644 +--- a/dwm.1 ++++ b/dwm.1 +@@ -19,14 +19,22 @@ layout applied. + 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. ++Each screen contains two small status bars. ++.P ++One bar 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 ++Another bar contains a tab for each window of the current view and allows ++navigation between windows, especially in the monocle mode. The different ++display modes of this bar are described under the Mod1\-w Keybord command ++section. When a single tag is selected, this tag is indicated in the left corner ++of the tab bar. + .P + dwm draws a small border around windows to indicate the focus state. + .SH OPTIONS +@@ -43,7 +51,8 @@ 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. ++label toggles between tiled and floating layout, click on a window name in the ++tab bar brings focus to that window. + .TP + .B Button3 + click on a tag label adds/removes all windows with that tag to/from the view. +@@ -104,6 +113,12 @@ Increase master area size. + .B Mod1\-h + Decrease master area size. + .TP ++.B Mod1\-w ++Cycle over the tab bar display modes: never displayed, always displayed, ++displayed only in monocle mode when the view contains more than one window (auto ++mode). Some display modes can be disabled in the configuration, config.h. In ++the default configuration only "never" and "auto" display modes are enabled. ++.TP + .B Mod1\-Return + Zooms/cycles focused window to/from master area (tiled layouts only). + .TP +diff --git a/dwm.c b/dwm.c +index 0362114..ff06772 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -64,7 +64,7 @@ enum { NetSupported, NetWMName, NetWMState, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ +-enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ++enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ + + typedef union { +@@ -111,24 +111,32 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++#define MAXTABS 50 ++ + struct Monitor { + char ltsymbol[16]; + float mfact; + int nmaster; + int num; + int by; /* bar geometry */ ++ int ty; /* tab bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; + int showbar; ++ int showtab; + int topbar; ++ int toptab; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; ++ Window tabwin; ++ int ntabs; ++ int tab_widths[MAXTABS]; + const Layout *lt[2]; + }; + +@@ -164,12 +172,15 @@ static void detachstack(Client *c); + static Monitor *dirtomon(int dir); + static void drawbar(Monitor *m); + static void drawbars(void); ++static void drawtab(Monitor *m); ++static void drawtabs(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 void focuswin(const Arg* arg); + static int getrootptr(int *x, int *y); + static long getstate(Window w); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); +@@ -206,6 +217,7 @@ static void setup(void); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static void tabmode(const Arg *arg); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *); +@@ -240,6 +252,7 @@ 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 th = 0; /* tab bar geometry */ + static int (*xerrorxlib)(Display *, XErrorEvent *); + static unsigned int numlockmask = 0; + static void (*handler[LASTEvent]) (XEvent *) = { +@@ -391,8 +404,9 @@ arrange(Monitor *m) + } + + void +-arrangemon(Monitor *m) +-{ ++arrangemon(Monitor *m) { ++ updatebarpos(m); ++ XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th); + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); + if (m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); +@@ -442,14 +456,33 @@ buttonpress(XEvent *e) + click = ClkStatusText; + else + click = ClkWinTitle; +- } else if ((c = wintoclient(ev->window))) { ++ } ++ if(ev->window == selmon->tabwin) { ++ i = 0; x = 0; ++ for(c = selmon->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ x += selmon->tab_widths[i]; ++ if (ev->x > x) ++ ++i; ++ else ++ break; ++ if(i >= m->ntabs) break; ++ } ++ if(c) { ++ click = ClkTabBar; ++ arg.ui = i; ++ } ++ } ++ else if((c = wintoclient(ev->window))) { + focus(c); + 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); ++ && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)){ ++ buttons[i].func(((click == ClkTagBar || click == ClkTabBar) ++ && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg); ++ } + } + + void +@@ -505,6 +538,8 @@ cleanupmon(Monitor *mon) + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); ++ XUnmapWindow(dpy, mon->tabwin); ++ XDestroyWindow(dpy, mon->tabwin); + free(mon); + } + +@@ -565,6 +600,7 @@ void + configurenotify(XEvent *e) + { + Monitor *m; ++ Client *c; + XConfigureEvent *ev = &e->xconfigure; + int dirty; + +@@ -576,8 +612,12 @@ configurenotify(XEvent *e) + if (updategeom() || dirty) { + drw_resize(drw, sw, bh); + updatebars(); +- for (m = mons; m; m = m->next) ++ for(m = mons; m; m = m->next){ ++ for (c = m->clients; c; c = c->next) ++ if (c->isfullscreen) ++ resizeclient(c, m->mx, m->my, m->mw, m->mh); + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); ++ } + focus(NULL); + arrange(NULL); + } +@@ -646,7 +686,10 @@ createmon(void) + m->mfact = mfact; + m->nmaster = nmaster; + m->showbar = showbar; ++ m->showtab = showtab; + m->topbar = topbar; ++ m->toptab = toptab; ++ m->ntabs = 0; + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); +@@ -763,6 +806,105 @@ drawbars(void) + } + + void ++drawtabs(void) { ++ Monitor *m; ++ ++ for(m = mons; m; m = m->next) ++ drawtab(m); ++} ++ ++static int ++cmpint(const void *p1, const void *p2) { ++ /* The actual arguments to this function are "pointers to ++ pointers to char", but strcmp(3) arguments are "pointers ++ to char", hence the following cast plus dereference */ ++ return *((int*) p1) > * (int*) p2; ++} ++ ++ ++void ++drawtab(Monitor *m) { ++ Client *c; ++ int i; ++ int itag = -1; ++ char view_info[50]; ++ int view_info_w = 0; ++ int sorted_label_widths[MAXTABS]; ++ int tot_width; ++ int maxsize = bh; ++ int x = 0; ++ int w = 0; ++ ++ //view_info: indicate the tag which is displayed in the view ++ for(i = 0; i < LENGTH(tags); ++i){ ++ if((selmon->tagset[selmon->seltags] >> i) & 1) { ++ if(itag >=0){ //more than one tag selected ++ itag = -1; ++ break; ++ } ++ itag = i; ++ } ++ } ++ ++ if(0 <= itag && itag < LENGTH(tags)){ ++ snprintf(view_info, sizeof view_info, "[%s]", tags[itag]); ++ } else { ++ strncpy(view_info, "[...]", sizeof view_info); ++ } ++ view_info[sizeof(view_info) - 1 ] = 0; ++ view_info_w = TEXTW(view_info); ++ tot_width = view_info_w; ++ ++ /* Calculates number of labels and their width */ ++ m->ntabs = 0; ++ for(c = m->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ m->tab_widths[m->ntabs] = TEXTW(c->name); ++ tot_width += m->tab_widths[m->ntabs]; ++ ++m->ntabs; ++ if(m->ntabs >= MAXTABS) break; ++ } ++ ++ if(tot_width > m->ww){ //not enough space to display the labels, they need to be truncated ++ memcpy(sorted_label_widths, m->tab_widths, sizeof(int) * m->ntabs); ++ qsort(sorted_label_widths, m->ntabs, sizeof(int), cmpint); ++ tot_width = view_info_w; ++ for(i = 0; i < m->ntabs; ++i){ ++ if(tot_width + (m->ntabs - i) * sorted_label_widths[i] > m->ww) ++ break; ++ tot_width += sorted_label_widths[i]; ++ } ++ maxsize = (m->ww - tot_width) / (m->ntabs - i); ++ } else{ ++ maxsize = m->ww; ++ } ++ i = 0; ++ for(c = m->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ if(i >= m->ntabs) break; ++ if(m->tab_widths[i] > maxsize) m->tab_widths[i] = maxsize; ++ w = m->tab_widths[i]; ++ drw_setscheme(drw, (c == m->sel) ? &scheme[SchemeSel] : &scheme[SchemeNorm]); ++ drw_text(drw, x, 0, w, th, c->name, 0); ++ x += w; ++ ++i; ++ } ++ ++ drw_setscheme(drw, &scheme[SchemeNorm]); ++ ++ /* cleans interspace between window names and current viewed tag label */ ++ w = m->ww - view_info_w - x; ++ drw_text(drw, x, 0, w, th, "", 0); ++ ++ /* view info */ ++ x += w; ++ w = view_info_w; ++ drw_text(drw, x, 0, w, th, view_info, 0); ++ ++ drw_map(drw, m->tabwin, 0, 0, m->ww, th); ++} ++ ++void + enternotify(XEvent *e) + { + Client *c; +@@ -787,8 +929,10 @@ 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); ++ drawtab(m); ++ } + } + + void +@@ -815,6 +959,7 @@ focus(Client *c) + } + selmon->sel = c; + drawbars(); ++ drawtabs(); + } + + /* there are some broken focus acquiring clients */ +@@ -868,6 +1013,19 @@ focusstack(const Arg *arg) + } + } + ++void ++focuswin(const Arg* arg){ ++ int iwin = arg->i; ++ Client* c = NULL; ++ for(c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next){ ++ if(ISVISIBLE(c)) --iwin; ++ }; ++ if(c) { ++ focus(c); ++ restack(selmon); ++ } ++} ++ + Atom + getatomprop(Client *c, Atom prop) + { +@@ -1250,12 +1408,14 @@ propertynotify(XEvent *e) + case XA_WM_HINTS: + updatewmhints(c); + drawbars(); ++ drawtabs(); + break; + } + if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { + updatetitle(c); + if (c == c->mon->sel) + drawbar(c->mon); ++ drawtab(c->mon); + } + if (ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); +@@ -1369,6 +1529,7 @@ restack(Monitor *m) + XWindowChanges wc; + + drawbar(m); ++ drawtab(m); + if (!m->sel) + return; + if (m->sel->isfloating || !m->lt[m->sellt]->arrange) +@@ -1561,6 +1722,8 @@ setup(void) + if (!drw->fontcount) + die("no fonts could be loaded.\n"); + bh = drw->fonts[0]->h + 2; ++ th = bh; ++ + updategeom(); + /* init atoms */ + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); +@@ -1699,6 +1862,17 @@ togglebar(const Arg *arg) + } + + void ++tabmode(const Arg *arg) ++{ ++ if(arg && arg->i >= 0) ++ selmon->showtab = arg->ui % showtab_nmodes; ++ else ++ selmon->showtab = (selmon->showtab + 1 ) % showtab_nmodes; ++ arrange(selmon); ++} ++ ++ ++void + togglefloating(const Arg *arg) + { + if (!selmon->sel) +@@ -1809,20 +1983,44 @@ updatebars(void) + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); + XMapRaised(dpy, m->barwin); ++ m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen), ++ CopyFromParent, DefaultVisual(dpy, screen), ++ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); ++ XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor); ++ XMapRaised(dpy, m->tabwin); + } + } + + void + updatebarpos(Monitor *m) + { ++ Client *c; ++ int nvis = 0; ++ + 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 ++ if ( m->topbar ) ++ m->wy += bh; ++ } else { + m->by = -bh; ++ } ++ ++ for(c = m->clients; c; c = c->next){ ++ if(ISVISIBLE(c)) ++nvis; ++ } ++ ++ if(m->showtab == showtab_always ++ || ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->sellt]->arrange == monocle))){ ++ m->wh -= th; ++ m->ty = m->toptab ? m->wy : m->wy + m->wh; ++ if ( m->toptab ) ++ m->wy += th; ++ } else { ++ m->ty = -th; ++ } + } + + void +@@ -2063,7 +2261,7 @@ wintomon(Window w) + if (w == root && getrootptr(&x, &y)) + return recttomon(x, y, 1, 1); + for (m = mons; m; m = m->next) +- if (w == m->barwin) ++ if (w == m->barwin || w == m->tabwin) + return m; + if ((c = wintoclient(w))) + return c->mon; diff --git a/dwm.suckless.org/patches/dwm-6.1-urg-border.diff b/dwm.suckless.org/patches/dwm-6.1-urg-border.diff @@ -0,0 +1,61 @@ +From 8b7bc42822cd5924450bbfc9ed598f72254473ba Mon Sep 17 00:00:00 2001 +From: Alexander Huemer <alexander.huemer@xx.vu> +Date: Sat, 7 Mar 2015 21:45:48 +0100 +Subject: [PATCH] Make the borders of urgent windows a different color + +--- + config.def.h | 1 + + dwm.c | 10 ++++++++-- + 2 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 875885b..5276f02 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -8,6 +8,7 @@ static const char normfgcolor[] = "#bbbbbb"; + static const char selbordercolor[] = "#005577"; + static const char selbgcolor[] = "#005577"; + static const char selfgcolor[] = "#eeeeee"; ++static const char urgbordercolor[] = "#ff0000"; + static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const Bool showbar = True; /* False means no bar */ +diff --git a/dwm.c b/dwm.c +index c8fc7d7..0924ace 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -58,7 +58,7 @@ + + /* enums */ + enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ +-enum { SchemeNorm, SchemeSel, SchemeLast }; /* color schemes */ ++enum { SchemeNorm, SchemeSel, SchemeUrg, SchemeLast }; /* color schemes */ + enum { NetSupported, NetWMName, NetWMState, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ +@@ -1537,6 +1537,9 @@ setup(void) { + scheme[SchemeSel].border = drw_clr_create(drw, selbordercolor); + scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor); + scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor); ++ scheme[SchemeUrg].border = drw_clr_create(drw, urgbordercolor); ++ scheme[SchemeUrg].bg = drw_clr_create(drw, selbgcolor); ++ scheme[SchemeUrg].fg = drw_clr_create(drw, selfgcolor); + /* init bars */ + updatebars(); + updatestatus(); +@@ -1982,8 +1985,11 @@ updatewmhints(Client *c) { + wmh->flags &= ~XUrgencyHint; + XSetWMHints(dpy, c->win, wmh); + } +- else ++ else { + c->isurgent = (wmh->flags & XUrgencyHint) ? True : False; ++ if (c->isurgent) ++ XSetWindowBorder(dpy, c->win, scheme[SchemeUrg].border->pix); ++ } + if(wmh->flags & InputHint) + c->neverfocus = !wmh->input; + else +-- +2.1.4 + diff --git a/dwm.suckless.org/patches/dwm-6.1-uselessgap.diff b/dwm.suckless.org/patches/dwm-6.1-uselessgap.diff @@ -1,15 +1,7 @@ -commit 6d7963f16af5ce9e14deab86efb3a68a5c420268 -Author: jeromenerf <jerome.andrieux@gmail.com> -Date: Sat Aug 15 18:35:11 2015 +0200 - - Useless gap for 6.1 - -diff --git a/dwm.c b/dwm.c -index c9fdd49..783fcdb 100644 ---- a/dwm.c -+++ b/dwm.c -@@ -53,8 +53,8 @@ - #define ISVISIBLE(C) ISVISIBLEONTAG(C, C->mon->tagset[C->mon->seltags]) +--- dwm/dwm.c.orig 2015-11-22 13:26:16.664650238 -0700 ++++ dwm/dwm.c 2015-11-22 13:25:57.407984351 -0700 +@@ -52,8 +52,8 @@ + #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) #define MOUSEMASK (BUTTONMASK|PointerMotionMask) -#define WIDTH(X) ((X)->w + 2 * (X)->bw) @@ -19,13 +11,13 @@ index c9fdd49..783fcdb 100644 #define TAGMASK ((1 << LENGTH(tags)) - 1) #define TEXTW(X) (drw_text(drw, 0, 0, 0, 0, (X), 0) + drw->fonts[0]->h) -@@ -1316,12 +1317,34 @@ resize(Client *c, int x, int y, int w, int h, Bool interact) { - void - resizeclient(Client *c, int x, int y, int w, int h) { +@@ -1293,12 +1293,36 @@ void + resizeclient(Client *c, int x, int y, int w, int h) + { XWindowChanges wc; -+ unsigned int n; -+ unsigned int gapoffset; -+ unsigned int gapincr; ++ unsigned int n; ++ unsigned int gapoffset; ++ unsigned int gapincr; + Client *nbc; - c->oldx = c->x; c->x = wc.x = x; @@ -33,28 +25,30 @@ index c9fdd49..783fcdb 100644 - c->oldw = c->w; c->w = wc.width = w; - c->oldh = c->h; c->h = wc.height = h; wc.border_width = c->bw; -+ -+ // Get number of clients for the selected monitor -+ for(n = 0, nbc = nexttiled(selmon->clients); nbc; nbc = nexttiled(nbc->next), n++); -+ // Do nothing if layout is floating -+ if(c->isfloating || selmon->lt[selmon->sellt]->arrange == NULL) { -+ gapincr = gapoffset = 0 ; -+ } else { -+ // Remove border and gap if layout is monocle or only one client ++ ++ /* Get number of clients for the selected monitor */ ++ for (n = 0, nbc = nexttiled(selmon->clients); nbc; nbc = nexttiled(nbc->next), n++); ++ ++ /* Do nothing if layout is floating */ ++ if (c->isfloating || selmon->lt[selmon->sellt]->arrange == NULL) { ++ gapincr = gapoffset = 0; ++ } else { ++ /* Remove border and gap if layout is monocle or only one client */ + if (selmon->lt[selmon->sellt]->arrange == monocle || n == 1) { -+ gapoffset = 0; -+ gapincr = -2 * borderpx ; -+ wc.border_width = 0; -+ } else { -+ gapoffset = gappx ; -+ gapincr = 2 * gappx ; -+ } ++ gapoffset = 0; ++ gapincr = -2 * borderpx; ++ wc.border_width = 0; ++ } else { ++ gapoffset = gappx; ++ gapincr = 2 * gappx; ++ } + } + -+ c->oldx = c->x; c->x = wc.x = x + gapoffset ; -+ c->oldy = c->y; c->y = wc.y = y + gapoffset ; -+ c->oldw = c->w; c->w = wc.width = w - gapincr ; -+ c->oldh = c->h; c->h = wc.height = h - gapincr ; ++ c->oldx = c->x; c->x = wc.x = x + gapoffset; ++ c->oldy = c->y; c->y = wc.y = y + gapoffset; ++ c->oldw = c->w; c->w = wc.width = w - gapincr; ++ c->oldh = c->h; c->h = wc.height = h - gapincr; ++ XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); configure(c); XSync(dpy, False); diff --git a/dwm.suckless.org/patches/dwm-6.1-warp.diff b/dwm.suckless.org/patches/dwm-6.1-warp.diff @@ -0,0 +1,57 @@ +diff -ruN dwm-6.1-orig/dwm.c dwm-6.1/dwm.c +--- dwm-6.1-orig/dwm.c 2015-11-08 16:39:37.000000000 -0600 ++++ dwm-6.1/dwm.c 2015-12-14 19:17:19.656091228 -0600 +@@ -227,6 +227,7 @@ + static void updatetitle(Client *c); + static void updatewmhints(Client *c); + static void view(const Arg *arg); ++static void warp(const Client *c); + static Client *wintoclient(Window w); + static Monitor *wintomon(Window w); + static int xerror(Display *dpy, XErrorEvent *ee); +@@ -840,6 +841,7 @@ + in gedit and anjuta */ + selmon = m; + focus(NULL); ++ warp(selmon->sel); + } + + void +@@ -1384,6 +1386,8 @@ + } + XSync(dpy, False); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); ++ if (m == selmon && (m->tagset[m->seltags] & m->sel->tags)) ++ warp(m->sel); + } + + void +@@ -2040,6 +2044,28 @@ + arrange(selmon); + } + ++void ++warp(const Client *c) ++{ ++ int x, y; ++ ++ if (!c) { ++ XWarpPointer(dpy, None, root, 0, 0, 0, 0, selmon->wx + selmon->ww/2, selmon->wy + selmon->wh/2); ++ return; ++ } ++ ++ if (!getrootptr(&x, &y) || ++ (x > c->x - c->bw && ++ y > c->y - c->bw && ++ x < c->x + c->w + c->bw*2 && ++ y < c->y + c->h + c->bw*2) || ++ (y > c->mon->by && y < c->mon->by + bh) || ++ (c->mon->topbar && !y)) ++ return; ++ ++ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w / 2, c->h / 2); ++} ++ + Client * + wintoclient(Window w) + { diff --git a/dwm.suckless.org/patches/dwm-10e232f9ace7-attachabove.diff b/dwm.suckless.org/patches/dwm-git-20120406-attachabove.diff diff --git a/dwm.suckless.org/patches/dwm-10e232f9ace7-pertag.diff b/dwm.suckless.org/patches/dwm-git-20120406-pertag.diff diff --git a/dwm.suckless.org/patches/dwm-c794a9f5ae5e-systray.diff b/dwm.suckless.org/patches/dwm-git-20130119-systray.diff diff --git a/dwm.suckless.org/patches/dwm-git-20160103-systray.diff b/dwm.suckless.org/patches/dwm-git-20160103-systray.diff @@ -0,0 +1,689 @@ +diff --git a/config.def.h b/config.def.h +index 7054c06..8393a58 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -13,6 +13,10 @@ static const char selbgcolor[] = "#005577"; + static const char selfgcolor[] = "#eeeeee"; + static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ ++static const 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, 0: 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 */ + +diff --git a/dwm.c b/dwm.c +index ff7e096..cf0b3a9 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -57,12 +57,30 @@ + #define TAGMASK ((1 << LENGTH(tags)) - 1) + #define TEXTW(X) (drw_text(drw, 0, 0, 0, 0, (X), 0) + drw->fonts[0]->h) + ++#define SYSTEM_TRAY_REQUEST_DOCK 0 ++#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0 ++ ++/* XEMBED messages */ ++#define XEMBED_EMBEDDED_NOTIFY 0 ++#define XEMBED_WINDOW_ACTIVATE 1 ++#define XEMBED_FOCUS_IN 4 ++#define XEMBED_MODALITY_ON 10 ++ ++#define XEMBED_MAPPED (1 << 0) ++#define XEMBED_WINDOW_ACTIVATE 1 ++#define XEMBED_WINDOW_DEACTIVATE 2 ++ ++#define VERSION_MAJOR 0 ++#define VERSION_MINOR 0 ++#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR ++ + /* enums */ + enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ + enum { SchemeNorm, SchemeSel, SchemeLast }; /* color schemes */ +-enum { NetSupported, NetWMName, NetWMState, +- NetWMFullscreen, NetActiveWindow, NetWMWindowType, +- NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ ++enum { NetSupported, NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, ++ NetWMName, NetWMState, 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); +@@ -170,8 +194,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); +@@ -189,13 +215,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 setup(void); + 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,24 @@ static void updateclientlist(void); + static void updatenumlockmask(void); + static void updatesizehints(Client *c); + static void updatestatus(void); ++static void updatesystray(void); ++static void updatesystrayicongeom(Client *i, int w, int h); ++static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); + static void updatewindowtype(Client *c); + static void updatetitle(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 unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ; + static const char broken[] = "broken"; + static char stext[256]; + static int screen; +@@ -256,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 ClrScheme scheme[SchemeLast]; +@@ -479,6 +516,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 < SchemeLast; i++) { +@@ -524,9 +566,50 @@ clearurgent(Client *c) + 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)); ++ c->win = cme->data.l[2]; ++ c->mon = selmon; ++ c->next = systray->icons; ++ systray->icons = c; ++ XGetWindowAttributes(dpy, c->win, &wa); ++ c->x = c->oldx = c->y = c->oldy = 0; ++ c->w = c->oldw = wa.width; ++ c->h = c->oldh = wa.height; ++ c->oldbw = wa.border_width; ++ c->bw = 0; ++ c->isfloating = True; ++ /* reuse tags field as mapped status */ ++ c->tags = 1; ++ updatesizehints(c); ++ updatesystrayicongeom(c, wa.width, wa.height); ++ XAddToSaveSet(dpy, c->win); ++ XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); ++ XReparentWindow(dpy, c->win, systray->win, 0, 0); ++ /* use parents background color */ ++ swa.background_pixel = scheme[SchemeNorm].bg->pix; ++ 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]) { +@@ -581,7 +664,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); +@@ -666,6 +749,11 @@ destroynotify(XEvent *e) + + if ((c = wintoclient(ev->window))) + unmanage(c, 1); ++ else if ((c = wintosystrayicon(ev->window))) { ++ removesystrayicon(c); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + } + + void +@@ -715,6 +803,7 @@ drawbar(Monitor *m) + + dx = (drw->fonts[0]->ascent + drw->fonts[0]->descent + 2) / 4; + ++ resizebarwin(m); + for (c = m->clients; c; c = c->next) { + occ |= c->tags; + if (c->isurgent) +@@ -737,6 +826,9 @@ drawbar(Monitor *m) + if (m == selmon) { /* status is only drawn on selected monitor */ + w = TEXTW(stext); + x = m->ww - w; ++ if (showsystray && m == systraytomon(m)) { ++ x -= getsystraywidth(); ++ } + if (x < xx) { + x = xx; + w = m->ww - xx; +@@ -765,6 +857,7 @@ drawbars(void) + + for (m = mons; m; m = m->next) + drawbar(m); ++ updatesystray(); + } + + void +@@ -792,8 +885,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 +@@ -880,10 +976,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; +@@ -917,6 +1020,15 @@ 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) + { +@@ -1023,7 +1135,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); +@@ -1110,6 +1222,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; +@@ -1237,6 +1355,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) +@@ -1288,6 +1416,19 @@ recttomon(int x, int y, int w, int h) + } + + 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)) +@@ -1295,6 +1436,14 @@ resize(Client *c, int x, int y, int w, int h, int interact) + } + + 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; +@@ -1367,6 +1516,18 @@ 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) + { + Client *c; +@@ -1455,26 +1616,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; + } +@@ -1488,7 +1659,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 +@@ -1574,12 +1745,18 @@ 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[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); + netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", 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); +@@ -1591,6 +1768,8 @@ setup(void) + scheme[SchemeSel].border = drw_clr_create(drw, selbordercolor); + scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor); + scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor); ++ /* init system tray */ ++ updatesystray(); + /* init bars */ + updatebars(); + updatestatus(); +@@ -1650,6 +1829,22 @@ spawn(const Arg *arg) + } + } + ++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 + tag(const Arg *arg) + { +@@ -1699,7 +1894,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); + } + +@@ -1795,11 +2001,17 @@ unmapnotify(XEvent *e) + else + unmanage(c, 0); + } ++ else if ((c = wintosystrayicon(ev->window))) { ++ removesystrayicon(c); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + } + + void + updatebars(void) + { ++ unsigned int w; + Monitor *m; + XSetWindowAttributes wa = { + .override_redirect = True, +@@ -1809,10 +2021,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); + } + } +@@ -2003,6 +2220,117 @@ updatestatus(void) + } + + 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 dimenons 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].bg->pix); ++ wa.event_mask = ButtonPressMask | ExposureMask; ++ wa.override_redirect = True; ++ wa.background_pixel = scheme[SchemeNorm].bg->pix; ++ XSelectInput(dpy, systray->win, SubstructureNotifyMask); ++ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, ++ PropModeReplace, (unsigned char *)&systrayorientation, 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].bg->pix; ++ 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].bg->pix); ++ XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); ++ XSync(dpy, False); ++} ++ ++void + updatewindowtype(Client *c) + { + Atom state = getatomprop(c, netatom[NetWMState]); +@@ -2075,6 +2403,16 @@ wintomon(Window w) + return selmon; + } + ++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; ++} ++ + /* There's no way to check accesses to destroyed windows, thus those cases are + * ignored (especially on UnmapNotify's). Other types of errors call Xlibs + * default error handler, which may call exit. */ diff --git a/dwm.suckless.org/patches/dwm-master_2015-12-19_3465be-pertag-tab-v2b.diff b/dwm.suckless.org/patches/dwm-master_2015-12-19_3465be-pertag-tab-v2b.diff @@ -0,0 +1,844 @@ +diff --git a/config.def.h b/config.def.h +index 7054c06..f0b33c5 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -15,10 +15,21 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ ++/* Display modes of the tab bar: never shown, always shown, shown only in */ ++/* monocle mode in presence of several windows. */ ++/* Modes after showtab_nmodes are disabled */ ++enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always}; ++static const int showtab = showtab_auto; /* Default tab bar show mode */ ++static const Bool toptab = False; /* False means bottom tab bar */ + + /* tagging */ + static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + ++/* default layout per tags */ ++/* The first element is for all-tag view, following i-th element corresponds to */ ++/* tags[i]. Layout is referred using the layouts array index.*/ ++static int def_layouts[1 + LENGTH(tags)] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; ++ + static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class +@@ -62,6 +73,7 @@ static Key keys[] = { + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, + { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_b, togglebar, {0} }, ++ { MODKEY, XK_w, tabmode, {-1} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, +@@ -109,5 +121,6 @@ static Button buttons[] = { + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, ++ { ClkTabBar, 0, Button1, focuswin, {0} }, + }; + +diff --git a/dwm.1 b/dwm.1 +index 6687011..077d92b 100644 +--- a/dwm.1 ++++ b/dwm.1 +@@ -19,14 +19,22 @@ layout applied. + 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. ++Each screen contains two small status bars. ++.P ++One bar 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 ++Another bar contains a tab for each window of the current view and allows ++navigation between windows, especially in the monocle mode. The different ++display modes of this bar are described under the Mod1\-w Keybord command ++section. When a single tag is selected, that tag is indicated in the left corner ++of the tab bar. + .P + dwm draws a small border around windows to indicate the focus state. + .SH OPTIONS +@@ -43,7 +51,8 @@ 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. ++label toggles between tiled and floating layout, click on a window name in the ++tab bar brings focus to that window. + .TP + .B Button3 + click on a tag label adds/removes all windows with that tag to/from the view. +@@ -104,6 +113,12 @@ Increase master area size. + .B Mod1\-h + Decrease master area size. + .TP ++.B Mod1\-w ++Cycle over the tab bar display modes: never displayed, always displayed, ++displayed only in monocle mode when the view contains than one window (auto ++mode). Some display modes can be disabled in the configuration, config.h. In ++the default configuration only "never" and "auto" display modes are enabled. ++.TP + .B Mod1\-Return + Zooms/cycles focused window to/from master area (tiled layouts only). + .TP +diff --git a/dwm.c b/dwm.c +index ff7e096..830d2c2 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -64,7 +64,7 @@ enum { NetSupported, NetWMName, NetWMState, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ +-enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ++enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ + + typedef union { +@@ -111,25 +111,35 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++#define MAXTABS 50 ++ ++typedef struct Pertag Pertag; + struct Monitor { + char ltsymbol[16]; + float mfact; + int nmaster; + int num; + int by; /* bar geometry */ ++ int ty; /* tab bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; + int showbar; ++ int showtab; + int topbar; ++ int toptab; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; ++ Window tabwin; ++ int ntabs; ++ int tab_widths[MAXTABS]; + const Layout *lt[2]; ++ Pertag *pertag; + }; + + typedef struct { +@@ -164,12 +174,15 @@ static void detachstack(Client *c); + static Monitor *dirtomon(int dir); + static void drawbar(Monitor *m); + static void drawbars(void); ++static void drawtab(Monitor *m); ++static void drawtabs(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 void focuswin(const Arg* arg); + static int getrootptr(int *x, int *y); + static long getstate(Window w); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); +@@ -206,6 +219,7 @@ static void setup(void); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static void tabmode(const Arg *arg); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *); +@@ -240,6 +254,7 @@ 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 th = 0; /* tab bar geometry */ + static int (*xerrorxlib)(Display *, XErrorEvent *); + static unsigned int numlockmask = 0; + static void (*handler[LASTEvent]) (XEvent *) = { +@@ -270,6 +285,16 @@ static Window root; + /* configuration, allows nested code to access above variables */ + #include "config.h" + ++struct Pertag { ++ unsigned int curtag, prevtag; /* current and previous tag */ ++ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ ++ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ ++ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ ++ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ ++ Bool showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ ++ Client *prevzooms[LENGTH(tags) + 1]; /* store zoom information */ ++}; ++ + /* compile-time check if all tags fit into an unsigned int bit array. */ + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +@@ -393,6 +418,8 @@ arrange(Monitor *m) + void + arrangemon(Monitor *m) + { ++ updatebarpos(m); ++ XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th); + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); + if (m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); +@@ -442,14 +469,33 @@ buttonpress(XEvent *e) + click = ClkStatusText; + else + click = ClkWinTitle; +- } else if ((c = wintoclient(ev->window))) { ++ } ++ if(ev->window == selmon->tabwin) { ++ i = 0; x = 0; ++ for(c = selmon->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ x += selmon->tab_widths[i]; ++ if (ev->x > x) ++ ++i; ++ else ++ break; ++ if(i >= m->ntabs) break; ++ } ++ if(c) { ++ click = ClkTabBar; ++ arg.ui = i; ++ } ++ } ++ else if((c = wintoclient(ev->window))) { + focus(c); + 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); ++ 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 || click == ClkTabBar) ++ && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg); ++ } + } + + void +@@ -469,23 +515,24 @@ 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); ++ while(m->stack) ++ unmanage(m->stack, False); + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); +- for (i = 0; i < CurLast; i++) +- drw_cur_free(drw, cursor[i]); +- for (i = 0; i < SchemeLast; i++) { +- drw_clr_free(scheme[i].border); +- drw_clr_free(scheme[i].bg); +- drw_clr_free(scheme[i].fg); +- } ++ drw_cur_free(drw, cursor[CurNormal]); ++ drw_cur_free(drw, cursor[CurResize]); ++ drw_cur_free(drw, cursor[CurMove]); ++ drw_clr_free(scheme[SchemeNorm].border); ++ drw_clr_free(scheme[SchemeNorm].bg); ++ drw_clr_free(scheme[SchemeNorm].fg); ++ drw_clr_free(scheme[SchemeSel].border); ++ drw_clr_free(scheme[SchemeSel].bg); ++ drw_clr_free(scheme[SchemeSel].fg); + drw_free(drw); + XSync(dpy, False); + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); +@@ -505,6 +552,8 @@ cleanupmon(Monitor *mon) + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); ++ XUnmapWindow(dpy, mon->tabwin); ++ XDestroyWindow(dpy, mon->tabwin); + free(mon); + } + +@@ -526,6 +575,7 @@ clientmessage(XEvent *e) + { + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); ++ int i; + + if (!c) + return; +@@ -537,6 +587,8 @@ clientmessage(XEvent *e) + if (!ISVISIBLE(c)) { + c->mon->seltags ^= 1; + c->mon->tagset[c->mon->seltags] = c->tags; ++ for(i=0; !(c->tags & 1 << i); i++); ++ view(&(Arg){.ui = 1 << i}); + } + pop(c); + } +@@ -565,11 +617,10 @@ void + configurenotify(XEvent *e) + { + Monitor *m; +- Client *c; + XConfigureEvent *ev = &e->xconfigure; + int dirty; + +- /* TODO: updategeom handling sucks, needs to be simplified */ ++ // TODO: updategeom handling sucks, needs to be simplified + if (ev->window == root) { + dirty = (sw != ev->width || sh != ev->height); + sw = ev->width; +@@ -577,10 +628,9 @@ configurenotify(XEvent *e) + 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); ++ //refreshing display of status bar. The tab bar is handled by the arrange() ++ //method, which is called below ++ for (m = mons; m; m = m->next){ + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); + } + focus(NULL); +@@ -645,16 +695,41 @@ Monitor * + createmon(void) + { + Monitor *m; ++ int i; + + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; + m->mfact = mfact; + m->nmaster = nmaster; + m->showbar = showbar; ++ m->showtab = showtab; + m->topbar = topbar; +- m->lt[0] = &layouts[0]; ++ m->toptab = toptab; ++ m->ntabs = 0; ++ m->lt[0] = &layouts[def_layouts[1] % LENGTH(layouts)]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); ++ if(!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Pertag)); ++ m->pertag->curtag = m->pertag->prevtag = 1; ++ for(i=0; i <= LENGTH(tags); i++) { ++ /* init nmaster */ ++ m->pertag->nmasters[i] = m->nmaster; ++ ++ /* init mfacts */ ++ m->pertag->mfacts[i] = m->mfact; ++ ++ /* init layouts */ ++ m->pertag->ltidxs[i][0] = &layouts[def_layouts[i % LENGTH(def_layouts)] % LENGTH(layouts)]; ++ m->pertag->ltidxs[i][1] = m->lt[1]; ++ m->pertag->sellts[i] = m->sellt; ++ ++ /* init showbar */ ++ m->pertag->showbars[i] = m->showbar; ++ ++ /* swap focus and zoomswap*/ ++ m->pertag->prevzooms[i] = NULL; ++ } + return m; + } + +@@ -768,6 +843,104 @@ drawbars(void) + } + + void ++drawtabs(void) { ++ Monitor *m; ++ ++ for(m = mons; m; m = m->next) ++ drawtab(m); ++} ++ ++static int ++cmpint(const void *p1, const void *p2) { ++ /* The actual arguments to this function are "pointers to ++ pointers to char", but strcmp(3) arguments are "pointers ++ to char", hence the following cast plus dereference */ ++ return *((int*) p1) > * (int*) p2; ++} ++ ++ ++void ++drawtab(Monitor *m) { ++ Client *c; ++ int i; ++ int itag = -1; ++ char view_info[50]; ++ int view_info_w = 0; ++ int sorted_label_widths[MAXTABS]; ++ int tot_width; ++ int maxsize = bh; ++ int x = 0; ++ int w = 0; ++ ++ //view_info: indicate the tag which is displayed in the view ++ for(i = 0; i < LENGTH(tags); ++i){ ++ if((selmon->tagset[selmon->seltags] >> i) & 1) { ++ if(itag >=0){ //more than one tag selected ++ itag = -1; ++ break; ++ } ++ itag = i; ++ } ++ } ++ if(0 <= itag && itag < LENGTH(tags)){ ++ snprintf(view_info, sizeof view_info, "[%s]", tags[itag]); ++ } else { ++ strncpy(view_info, "[...]", sizeof view_info); ++ } ++ view_info[sizeof(view_info) - 1 ] = 0; ++ view_info_w = TEXTW(view_info); ++ tot_width = view_info_w; ++ ++ /* Calculates number of labels and their width */ ++ m->ntabs = 0; ++ for(c = m->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ m->tab_widths[m->ntabs] = TEXTW(c->name); ++ tot_width += m->tab_widths[m->ntabs]; ++ ++m->ntabs; ++ if(m->ntabs >= MAXTABS) break; ++ } ++ ++ if(tot_width > m->ww){ //not enough space to display the labels, they need to be truncated ++ memcpy(sorted_label_widths, m->tab_widths, sizeof(int) * m->ntabs); ++ qsort(sorted_label_widths, m->ntabs, sizeof(int), cmpint); ++ tot_width = view_info_w; ++ for(i = 0; i < m->ntabs; ++i){ ++ if(tot_width + (m->ntabs - i) * sorted_label_widths[i] > m->ww) ++ break; ++ tot_width += sorted_label_widths[i]; ++ } ++ maxsize = (m->ww - tot_width) / (m->ntabs - i); ++ } else{ ++ maxsize = m->ww; ++ } ++ i = 0; ++ for(c = m->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ if(i >= m->ntabs) break; ++ if(m->tab_widths[i] > maxsize) m->tab_widths[i] = maxsize; ++ w = m->tab_widths[i]; ++ drw_setscheme(drw, (c == m->sel) ? &scheme[SchemeSel] : &scheme[SchemeNorm]); ++ drw_text(drw, x, 0, w, th, c->name, 0); ++ x += w; ++ ++i; ++ } ++ ++ drw_setscheme(drw, &scheme[SchemeNorm]); ++ ++ /* cleans interspace between window names and current viewed tag label */ ++ w = m->ww - view_info_w - x; ++ drw_text(drw, x, 0, w, th, "", 0); ++ ++ /* view info */ ++ x += w; ++ w = view_info_w; ++ drw_text(drw, x, 0, w, th, view_info, 0); ++ ++ drw_map(drw, m->tabwin, 0, 0, m->ww, th); ++} ++ ++void + enternotify(XEvent *e) + { + Client *c; +@@ -792,8 +965,10 @@ 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); ++ drawtab(m); ++ } + } + + void +@@ -811,7 +986,7 @@ focus(Client *c) + clearurgent(c); + detachstack(c); + attachstack(c); +- grabbuttons(c, 1); ++ grabbuttons(c, True); + XSetWindowBorder(dpy, c->win, scheme[SchemeSel].border->pix); + setfocus(c); + } else { +@@ -820,6 +995,7 @@ focus(Client *c) + } + selmon->sel = c; + drawbars(); ++ drawtabs(); + } + + /* there are some broken focus acquiring clients */ +@@ -873,6 +1049,19 @@ focusstack(const Arg *arg) + } + } + ++void ++focuswin(const Arg* arg){ ++ int iwin = arg->i; ++ Client* c = NULL; ++ for(c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next){ ++ if(ISVISIBLE(c)) --iwin; ++ }; ++ if(c) { ++ focus(c); ++ restack(selmon); ++ } ++} ++ + Atom + getatomprop(Client *c, Atom prop) + { +@@ -986,7 +1175,7 @@ grabkeys(void) + void + incnmaster(const Arg *arg) + { +- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); + } + +@@ -1144,7 +1333,7 @@ motionnotify(XEvent *e) + if (ev->window != root) + return; + if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { +- unfocus(selmon->sel, 1); ++ unfocus(selmon->sel, True); + selmon = m; + focus(NULL); + } +@@ -1164,11 +1353,13 @@ movemouse(const Arg *arg) + return; + if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ + 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) ++ None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) + return; + if (!getrootptr(&x, &y)) + return; +@@ -1255,12 +1446,14 @@ propertynotify(XEvent *e) + case XA_WM_HINTS: + updatewmhints(c); + drawbars(); ++ drawtabs(); + break; + } + if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { + updatetitle(c); + if (c == c->mon->sel) + drawbar(c->mon); ++ drawtab(c->mon); + } + if (ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); +@@ -1322,11 +1515,13 @@ resizemouse(const Arg *arg) + return; + if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ + 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) ++ 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 { +@@ -1374,6 +1569,7 @@ restack(Monitor *m) + XWindowChanges wc; + + drawbar(m); ++ drawtab(m); + if (!m->sel) + return; + if (m->sel->isfloating || !m->lt[m->sellt]->arrange) +@@ -1482,11 +1678,11 @@ sendevent(Client *c, Atom proto) + void + setfocus(Client *c) + { +- if (!c->neverfocus) { ++ if(!c->neverfocus) { + XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); + XChangeProperty(dpy, root, netatom[NetActiveWindow], +- XA_WINDOW, 32, PropModeReplace, +- (unsigned char *) &(c->win), 1); ++ XA_WINDOW, 32, PropModeReplace, ++ (unsigned char *) &(c->win), 1); + } + sendevent(c, wmatom[WMTakeFocus]); + } +@@ -1522,10 +1718,13 @@ setfullscreen(Client *c, int fullscreen) + 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; ++ if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) { ++ selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ } ++ if(arg && arg->v) ++ selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if (selmon->sel) + arrange(selmon); +@@ -1544,7 +1743,7 @@ setmfact(const Arg *arg) + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if (f < 0.1 || f > 0.9) + return; +- selmon->mfact = f; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; + arrange(selmon); + } + +@@ -1564,8 +1763,9 @@ setup(void) + drw = drw_create(dpy, screen, root, sw, sh); + drw_load_fonts(drw, fonts, LENGTH(fonts)); + if (!drw->fontcount) +- die("no fonts could be loaded.\n"); ++ die("No fonts could be loaded.\n"); + bh = drw->fonts[0]->h + 2; ++ th = bh; + updategeom(); + /* init atoms */ + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); +@@ -1637,10 +1837,10 @@ sigchld(int unused) + void + spawn(const Arg *arg) + { +- if (arg->v == dmenucmd) ++ if(arg->v == dmenucmd) + dmenumon[0] = '0' + selmon->num; +- if (fork() == 0) { +- if (dpy) ++ if(fork() == 0) { ++ if(dpy) + close(ConnectionNumber(dpy)); + setsid(); + execvp(((char **)arg->v)[0], (char **)arg->v); +@@ -1697,18 +1897,29 @@ tile(Monitor *m) + void + togglebar(const Arg *arg) + { +- selmon->showbar = !selmon->showbar; ++ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; + updatebarpos(selmon); + XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); + arrange(selmon); + } + + void ++tabmode(const Arg *arg) ++{ ++ if(arg && arg->i >= 0) ++ selmon->showtab = arg->ui % showtab_nmodes; ++ else ++ selmon->showtab = (selmon->showtab + 1 ) % showtab_nmodes; ++ arrange(selmon); ++} ++ ++ ++void + togglefloating(const Arg *arg) + { +- if (!selmon->sel) ++ if(!selmon->sel) + return; +- if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ ++ if(selmon->sel->isfullscreen) /* no support for fullscreen windows */ + return; + selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed; + if (selmon->sel->isfloating) +@@ -1736,9 +1947,29 @@ void + toggleview(const Arg *arg) + { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); ++ int i; + + if (newtagset) { ++ if(newtagset == ~0) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = 0; ++ } ++ /* test if the user did not select the same tag */ ++ if(!(newtagset & 1 << (selmon->pertag->curtag - 1))) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ for (i=0; !(newtagset & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } + selmon->tagset[selmon->seltags] = newtagset; ++ ++ /* apply settings for this view */ ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); + focus(NULL); + arrange(selmon); + } +@@ -1749,7 +1980,7 @@ unfocus(Client *c, int setfocus) + { + if (!c) + return; +- grabbuttons(c, 0); ++ grabbuttons(c, False); + XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].border->pix); + if (setfocus) { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); +@@ -1814,20 +2045,44 @@ updatebars(void) + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); + XMapRaised(dpy, m->barwin); ++ m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen), ++ CopyFromParent, DefaultVisual(dpy, screen), ++ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); ++ XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor); ++ XMapRaised(dpy, m->tabwin); + } + } + + void + updatebarpos(Monitor *m) + { ++ Client *c; ++ int nvis = 0; ++ + 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 ++ if ( m->topbar ) ++ m->wy += bh; ++ } else { + m->by = -bh; ++ } ++ ++ for(c = m->clients; c; c = c->next){ ++ if(ISVISIBLE(c)) ++nvis; ++ } ++ ++ if(m->showtab == showtab_always ++ || ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->sellt]->arrange == monocle))){ ++ m->wh -= th; ++ m->ty = m->toptab ? m->wy : m->wy + m->wh; ++ if ( m->toptab ) ++ m->wy += th; ++ } else { ++ m->ty = -th; ++ } + } + + void +@@ -2009,9 +2264,9 @@ updatewindowtype(Client *c) + Atom wtype = getatomprop(c, netatom[NetWMWindowType]); + + if (state == netatom[NetWMFullscreen]) +- setfullscreen(c, 1); ++ setfullscreen(c, True); + if (wtype == netatom[NetWMWindowTypeDialog]) +- c->isfloating = 1; ++ c->isfloating = True; + } + + void +@@ -2036,11 +2291,33 @@ updatewmhints(Client *c) + void + view(const Arg *arg) + { +- if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) ++ int i; ++ unsigned int tmptag; ++ ++ if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ +- if (arg->ui & TAGMASK) ++ if(arg->ui & TAGMASK) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; ++ if(arg->ui == ~0) ++ selmon->pertag->curtag = 0; ++ else { ++ for (i=0; !(arg->ui & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } ++ } else { ++ tmptag = selmon->pertag->prevtag; ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = tmptag; ++ } ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); + focus(NULL); + arrange(selmon); + } +@@ -2068,7 +2345,7 @@ wintomon(Window w) + if (w == root && getrootptr(&x, &y)) + return recttomon(x, y, 1, 1); + for (m = mons; m; m = m->next) +- if (w == m->barwin) ++ if(w == m->barwin || w == m->tabwin) + return m; + if ((c = wintoclient(w))) + return c->mon; diff --git a/dwm.suckless.org/patches/dwm-master_2015-12-19_3465be-tab-v2b.diff b/dwm.suckless.org/patches/dwm-master_2015-12-19_3465be-tab-v2b.diff @@ -0,0 +1,500 @@ +diff --git a/config.def.h b/config.def.h +index 7054c06..e784231 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -15,6 +15,12 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ ++/* Display modes of the tab bar: never shown, always shown, shown only in */ ++/* monocle mode in presence of several windows. */ ++/* Modes after showtab_nmodes are disabled */ ++enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always}; ++static const int showtab = showtab_auto; /* Default tab bar show mode */ ++static const int toptab = False; /* False means bottom tab bar */ + + /* tagging */ + static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; +@@ -62,6 +68,7 @@ static Key keys[] = { + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, + { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_b, togglebar, {0} }, ++ { MODKEY, XK_w, tabmode, {-1} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, +@@ -109,5 +116,6 @@ static Button buttons[] = { + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, ++ { ClkTabBar, 0, Button1, focuswin, {0} }, + }; + +diff --git a/dwm.1 b/dwm.1 +index 6687011..9ff827c 100644 +--- a/dwm.1 ++++ b/dwm.1 +@@ -19,14 +19,22 @@ layout applied. + 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. ++Each screen contains two small status bars. ++.P ++One bar 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 ++Another bar contains a tab for each window of the current view and allows ++navigation between windows, especially in the monocle mode. The different ++display modes of this bar are described under the Mod1\-w Keybord command ++section. When a single tag is selected, this tag is indicated in the left corner ++of the tab bar. + .P + dwm draws a small border around windows to indicate the focus state. + .SH OPTIONS +@@ -43,7 +51,8 @@ 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. ++label toggles between tiled and floating layout, click on a window name in the ++tab bar brings focus to that window. + .TP + .B Button3 + click on a tag label adds/removes all windows with that tag to/from the view. +@@ -104,6 +113,12 @@ Increase master area size. + .B Mod1\-h + Decrease master area size. + .TP ++.B Mod1\-w ++Cycle over the tab bar display modes: never displayed, always displayed, ++displayed only in monocle mode when the view contains more than one window (auto ++mode). Some display modes can be disabled in the configuration, config.h. In ++the default configuration only "never" and "auto" display modes are enabled. ++.TP + .B Mod1\-Return + Zooms/cycles focused window to/from master area (tiled layouts only). + .TP +diff --git a/dwm.c b/dwm.c +index ff7e096..fb285ec 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -64,7 +64,7 @@ enum { NetSupported, NetWMName, NetWMState, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ +-enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ++enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ + + typedef union { +@@ -111,24 +111,32 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++#define MAXTABS 50 ++ + struct Monitor { + char ltsymbol[16]; + float mfact; + int nmaster; + int num; + int by; /* bar geometry */ ++ int ty; /* tab bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; + int showbar; ++ int showtab; + int topbar; ++ int toptab; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; ++ Window tabwin; ++ int ntabs; ++ int tab_widths[MAXTABS]; + const Layout *lt[2]; + }; + +@@ -164,12 +172,15 @@ static void detachstack(Client *c); + static Monitor *dirtomon(int dir); + static void drawbar(Monitor *m); + static void drawbars(void); ++static void drawtab(Monitor *m); ++static void drawtabs(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 void focuswin(const Arg* arg); + static int getrootptr(int *x, int *y); + static long getstate(Window w); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); +@@ -206,6 +217,7 @@ static void setup(void); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static void tabmode(const Arg *arg); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *); +@@ -240,6 +252,7 @@ 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 th = 0; /* tab bar geometry */ + static int (*xerrorxlib)(Display *, XErrorEvent *); + static unsigned int numlockmask = 0; + static void (*handler[LASTEvent]) (XEvent *) = { +@@ -391,8 +404,9 @@ arrange(Monitor *m) + } + + void +-arrangemon(Monitor *m) +-{ ++arrangemon(Monitor *m) { ++ updatebarpos(m); ++ XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th); + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); + if (m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); +@@ -442,14 +456,33 @@ buttonpress(XEvent *e) + click = ClkStatusText; + else + click = ClkWinTitle; +- } else if ((c = wintoclient(ev->window))) { ++ } ++ if(ev->window == selmon->tabwin) { ++ i = 0; x = 0; ++ for(c = selmon->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ x += selmon->tab_widths[i]; ++ if (ev->x > x) ++ ++i; ++ else ++ break; ++ if(i >= m->ntabs) break; ++ } ++ if(c) { ++ click = ClkTabBar; ++ arg.ui = i; ++ } ++ } ++ else if((c = wintoclient(ev->window))) { + focus(c); + 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); ++ && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)){ ++ buttons[i].func(((click == ClkTagBar || click == ClkTabBar) ++ && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg); ++ } + } + + void +@@ -505,6 +538,8 @@ cleanupmon(Monitor *mon) + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); ++ XUnmapWindow(dpy, mon->tabwin); ++ XDestroyWindow(dpy, mon->tabwin); + free(mon); + } + +@@ -577,7 +612,9 @@ configurenotify(XEvent *e) + if (updategeom() || dirty) { + drw_resize(drw, sw, bh); + updatebars(); +- for (m = mons; m; m = m->next) { ++ //refreshing display of status bar. The tab bar is handled by the arrange() ++ //method, which is called below ++ 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); +@@ -651,7 +688,10 @@ createmon(void) + m->mfact = mfact; + m->nmaster = nmaster; + m->showbar = showbar; ++ m->showtab = showtab; + m->topbar = topbar; ++ m->toptab = toptab; ++ m->ntabs = 0; + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); +@@ -768,6 +808,105 @@ drawbars(void) + } + + void ++drawtabs(void) { ++ Monitor *m; ++ ++ for(m = mons; m; m = m->next) ++ drawtab(m); ++} ++ ++static int ++cmpint(const void *p1, const void *p2) { ++ /* The actual arguments to this function are "pointers to ++ pointers to char", but strcmp(3) arguments are "pointers ++ to char", hence the following cast plus dereference */ ++ return *((int*) p1) > * (int*) p2; ++} ++ ++ ++void ++drawtab(Monitor *m) { ++ Client *c; ++ int i; ++ int itag = -1; ++ char view_info[50]; ++ int view_info_w = 0; ++ int sorted_label_widths[MAXTABS]; ++ int tot_width; ++ int maxsize = bh; ++ int x = 0; ++ int w = 0; ++ ++ //view_info: indicate the tag which is displayed in the view ++ for(i = 0; i < LENGTH(tags); ++i){ ++ if((selmon->tagset[selmon->seltags] >> i) & 1) { ++ if(itag >=0){ //more than one tag selected ++ itag = -1; ++ break; ++ } ++ itag = i; ++ } ++ } ++ ++ if(0 <= itag && itag < LENGTH(tags)){ ++ snprintf(view_info, sizeof view_info, "[%s]", tags[itag]); ++ } else { ++ strncpy(view_info, "[...]", sizeof view_info); ++ } ++ view_info[sizeof(view_info) - 1 ] = 0; ++ view_info_w = TEXTW(view_info); ++ tot_width = view_info_w; ++ ++ /* Calculates number of labels and their width */ ++ m->ntabs = 0; ++ for(c = m->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ m->tab_widths[m->ntabs] = TEXTW(c->name); ++ tot_width += m->tab_widths[m->ntabs]; ++ ++m->ntabs; ++ if(m->ntabs >= MAXTABS) break; ++ } ++ ++ if(tot_width > m->ww){ //not enough space to display the labels, they need to be truncated ++ memcpy(sorted_label_widths, m->tab_widths, sizeof(int) * m->ntabs); ++ qsort(sorted_label_widths, m->ntabs, sizeof(int), cmpint); ++ tot_width = view_info_w; ++ for(i = 0; i < m->ntabs; ++i){ ++ if(tot_width + (m->ntabs - i) * sorted_label_widths[i] > m->ww) ++ break; ++ tot_width += sorted_label_widths[i]; ++ } ++ maxsize = (m->ww - tot_width) / (m->ntabs - i); ++ } else{ ++ maxsize = m->ww; ++ } ++ i = 0; ++ for(c = m->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ if(i >= m->ntabs) break; ++ if(m->tab_widths[i] > maxsize) m->tab_widths[i] = maxsize; ++ w = m->tab_widths[i]; ++ drw_setscheme(drw, (c == m->sel) ? &scheme[SchemeSel] : &scheme[SchemeNorm]); ++ drw_text(drw, x, 0, w, th, c->name, 0); ++ x += w; ++ ++i; ++ } ++ ++ drw_setscheme(drw, &scheme[SchemeNorm]); ++ ++ /* cleans interspace between window names and current viewed tag label */ ++ w = m->ww - view_info_w - x; ++ drw_text(drw, x, 0, w, th, "", 0); ++ ++ /* view info */ ++ x += w; ++ w = view_info_w; ++ drw_text(drw, x, 0, w, th, view_info, 0); ++ ++ drw_map(drw, m->tabwin, 0, 0, m->ww, th); ++} ++ ++void + enternotify(XEvent *e) + { + Client *c; +@@ -792,8 +931,10 @@ 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); ++ drawtab(m); ++ } + } + + void +@@ -820,6 +961,7 @@ focus(Client *c) + } + selmon->sel = c; + drawbars(); ++ drawtabs(); + } + + /* there are some broken focus acquiring clients */ +@@ -873,6 +1015,19 @@ focusstack(const Arg *arg) + } + } + ++void ++focuswin(const Arg* arg){ ++ int iwin = arg->i; ++ Client* c = NULL; ++ for(c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next){ ++ if(ISVISIBLE(c)) --iwin; ++ }; ++ if(c) { ++ focus(c); ++ restack(selmon); ++ } ++} ++ + Atom + getatomprop(Client *c, Atom prop) + { +@@ -1255,12 +1410,14 @@ propertynotify(XEvent *e) + case XA_WM_HINTS: + updatewmhints(c); + drawbars(); ++ drawtabs(); + break; + } + if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { + updatetitle(c); + if (c == c->mon->sel) + drawbar(c->mon); ++ drawtab(c->mon); + } + if (ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); +@@ -1374,6 +1531,7 @@ restack(Monitor *m) + XWindowChanges wc; + + drawbar(m); ++ drawtab(m); + if (!m->sel) + return; + if (m->sel->isfloating || !m->lt[m->sellt]->arrange) +@@ -1566,6 +1724,8 @@ setup(void) + if (!drw->fontcount) + die("no fonts could be loaded.\n"); + bh = drw->fonts[0]->h + 2; ++ th = bh; ++ + updategeom(); + /* init atoms */ + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); +@@ -1704,6 +1864,17 @@ togglebar(const Arg *arg) + } + + void ++tabmode(const Arg *arg) ++{ ++ if(arg && arg->i >= 0) ++ selmon->showtab = arg->ui % showtab_nmodes; ++ else ++ selmon->showtab = (selmon->showtab + 1 ) % showtab_nmodes; ++ arrange(selmon); ++} ++ ++ ++void + togglefloating(const Arg *arg) + { + if (!selmon->sel) +@@ -1814,20 +1985,44 @@ updatebars(void) + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); + XMapRaised(dpy, m->barwin); ++ m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen), ++ CopyFromParent, DefaultVisual(dpy, screen), ++ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); ++ XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor); ++ XMapRaised(dpy, m->tabwin); + } + } + + void + updatebarpos(Monitor *m) + { ++ Client *c; ++ int nvis = 0; ++ + 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 ++ if ( m->topbar ) ++ m->wy += bh; ++ } else { + m->by = -bh; ++ } ++ ++ for(c = m->clients; c; c = c->next){ ++ if(ISVISIBLE(c)) ++nvis; ++ } ++ ++ if(m->showtab == showtab_always ++ || ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->sellt]->arrange == monocle))){ ++ m->wh -= th; ++ m->ty = m->toptab ? m->wy : m->wy + m->wh; ++ if ( m->toptab ) ++ m->wy += th; ++ } else { ++ m->ty = -th; ++ } + } + + void +@@ -2068,7 +2263,7 @@ wintomon(Window w) + if (w == root && getrootptr(&x, &y)) + return recttomon(x, y, 1, 1); + for (m = mons; m; m = m->next) +- if (w == m->barwin) ++ if (w == m->barwin || w == m->tabwin) + return m; + if ((c = wintoclient(w))) + return c->mon; diff --git a/dwm.suckless.org/patches/exresize.md b/dwm.suckless.org/patches/exresize.md @@ -16,7 +16,7 @@ description. Download -------- - * [dwm-r1606-exresize.dif](dwm-r1606-exresize.diff) (20121117) + * [dwm-r1606-exresize.diff](dwm-r1606-exresize.diff) (20121117) Authors ------- diff --git a/dwm.suckless.org/patches/fancybar-c794a9f5ae5e.patch b/dwm.suckless.org/patches/fancybar-c794a9f5ae5e.patch @@ -1,124 +0,0 @@ ---- dwm.c.orig 2012-09-30 16:19:00.251353990 -0400 -+++ dwm.c 2012-09-30 16:18:06.436026937 -0400 -@@ -179,6 +179,7 @@ - static Monitor *dirtomon(int dir); - static void drawbar(Monitor *m); - static void drawbars(void); -+static void drawline(unsigned long col[ColLast]); - static void drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]); - static void drawtext(const char *text, unsigned long col[ColLast], Bool invert); - static void enternotify(XEvent *e); -@@ -721,12 +722,15 @@ - - void - drawbar(Monitor *m) { -- int x; -- unsigned int i, occ = 0, urg = 0; -+ int x, ow, mw = 0, extra, tw; -+ unsigned int i, n = 0, occ = 0, urg = 0; - unsigned long *col; -- Client *c; -+ Client *c, *firstvis, *lastvis = NULL; -+ DC seldc; - - for(c = m->clients; c; c = c->next) { -+ if(ISVISIBLE(c)) -+ n++; - occ |= c->tags; - if(c->isurgent) - urg |= c->tags; -@@ -755,16 +759,61 @@ - } - else - dc.x = m->ww; -- if((dc.w = dc.x - x) > bh) { -- dc.x = x; -- if(m->sel) { -- col = m == selmon ? dc.sel : dc.norm; -- drawtext(m->sel->name, col, False); -- drawsquare(m->sel->isfixed, m->sel->isfloating, False, col); -+ for(c = m->clients; c && !ISVISIBLE(c); c = c->next); -+ firstvis = c; -+ -+ col = m == selmon ? dc.sel : dc.norm; -+ dc.w = dc.x - x; -+ dc.x = x; -+ -+ if(n > 0) { -+ mw = dc.w / n; -+ extra = 0; -+ seldc = dc; -+ i = 0; -+ -+ while(c) { -+ lastvis = c; -+ tw = TEXTW(c->name); -+ if(tw < mw) extra += (mw - tw); else i++; -+ for(c = c->next; c && !ISVISIBLE(c); c = c->next); - } -- else -+ -+ if(i > 0) mw += extra / i; -+ -+ c = firstvis; -+ x = dc.x; -+ } -+ -+ while(dc.w > bh) { -+ if(c) { -+ ow = dc.w; -+ tw = TEXTW(c->name); -+ dc.w = MIN(ow, tw); -+ -+ if(dc.w > mw) dc.w = mw; -+ if(m->sel ==c) seldc = dc; -+ if(c == lastvis) dc.w = ow; -+ -+ drawtext(c->name, col, False); -+ if(c != firstvis) drawline(col); -+ drawsquare(c->isfixed, c->isfloating, False, col); -+ -+ dc.x += dc.w; -+ dc.w = ow - dc.w; -+ for(c = c->next; c&& !ISVISIBLE(c); c = c->next); -+ } else { - drawtext(NULL, dc.norm, False); -+ break; -+ } - } -+ -+ if(m == selmon && m->sel && ISVISIBLE(m->sel)) { -+ dc = seldc; -+ drawtext(m->sel->name, col, True); -+ drawsquare(m->sel->isfixed, m->sel->isfloating, True, col); -+ } -+ - XCopyArea(dpy, dc.drawable, m->barwin, dc.gc, 0, 0, m->ww, bh, 0, 0); - XSync(dpy, False); - } -@@ -778,6 +827,15 @@ - } - - void -+drawline(unsigned long col[ColLast]) { -+ XGCValues gcv; -+ -+ gcv.foreground = col[ColFG]; -+ XChangeGC(dpy, dc.gc, GCForeground, &gcv); -+ XDrawLine(dpy, dc.drawable, dc.gc, dc.x, dc.y, dc.x, dc.y + (dc.font.ascent + dc.font.descent + 2)); -+} -+ -+void - drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { - int x; - -@@ -1327,8 +1385,7 @@ - } - if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { - updatetitle(c); -- if(c == c->mon->sel) -- drawbar(c->mon); -+ drawbar(c->mon); - } - if(ev->atom == netatom[NetWMWindowType]) - updatewindowtype(c); diff --git a/dwm.suckless.org/patches/fancybar-r1496.diff b/dwm.suckless.org/patches/fancybar-r1496.diff @@ -1,126 +0,0 @@ -diff -r de4a2998e1f5 dwm.c ---- a/dwm.c Tue Sep 22 09:53:11 2009 +0100 -+++ b/dwm.c Tue Sep 22 12:32:15 2009 +0200 -@@ -171,6 +171,7 @@ - static Monitor *dirtomon(int dir); - static void drawbar(Monitor *m); - static void drawbars(void); -+static void drawvline(unsigned long col[ColLast]); - static void drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]); - static void drawtext(const char *text, unsigned long col[ColLast], Bool invert); - static void enternotify(XEvent *e); -@@ -668,12 +669,15 @@ - - void - drawbar(Monitor *m) { -- int x; -- unsigned int i, occ = 0, urg = 0; -+ int x, ow, mw = 0, extra, tw; -+ unsigned int i, n = 0, occ = 0, urg = 0; - unsigned long *col; -- Client *c; -+ Client *c, *firstvis, *lastvis = NULL; -+ DC seldc; - - for(c = m->clients; c; c = c->next) { -+ if(ISVISIBLE(c)) -+ n++; - occ |= c->tags; - if(c->isurgent) - urg |= c->tags; -@@ -702,16 +706,62 @@ - } - else - dc.x = m->ww; -- if((dc.w = dc.x - x) > bh) { -- dc.x = x; -- if(m->sel) { -- col = m == selmon ? dc.sel : dc.norm; -- drawtext(m->sel->name, col, False); -- drawsquare(m->sel->isfixed, m->sel->isfloating, False, col); -+ -+ for(c = m->clients; c && !ISVISIBLE(c); c = c->next); -+ firstvis = c; -+ -+ col = m == selmon ? dc.sel : dc.norm; -+ dc.w = dc.x - x; -+ dc.x = x; -+ -+ if(n > 0) { -+ mw = dc.w / n; -+ extra = 0; -+ seldc = dc; -+ i = 0; -+ -+ while(c) { -+ lastvis = c; -+ tw = TEXTW(c->name); -+ if(tw < mw) extra += (mw - tw); else i++; -+ for(c = c->next; c && !ISVISIBLE(c); c = c->next); - } -- else -+ -+ if(i > 0) mw += extra / i; -+ -+ c = firstvis; -+ x = dc.x; -+ } -+ -+ while(dc.w > bh) { -+ if(c) { -+ ow = dc.w; -+ tw = TEXTW(c->name); -+ dc.w = MIN(ow, tw); -+ -+ if(dc.w > mw) dc.w = mw; -+ if(m->sel == c) seldc = dc; -+ if(c == lastvis) dc.w = ow; -+ -+ drawtext(c->name, col, False); -+ if(c != firstvis) drawvline(col); -+ drawsquare(c->isfixed, c->isfloating, False, col); -+ -+ dc.x += dc.w; -+ dc.w = ow - dc.w; -+ for(c = c->next; c && !ISVISIBLE(c); c = c->next); -+ } else { - drawtext(NULL, dc.norm, False); -+ break; -+ } - } -+ -+ if(m == selmon && m->sel && ISVISIBLE(m->sel)) { -+ dc = seldc; -+ drawtext(m->sel->name, col, True); -+ drawsquare(m->sel->isfixed, m->sel->isfloating, True, col); -+ } -+ - XCopyArea(dpy, dc.drawable, m->barwin, dc.gc, 0, 0, m->ww, bh, 0, 0); - XSync(dpy, False); - } -@@ -725,6 +775,15 @@ - } - - void -+drawvline(unsigned long col[ColLast]) { -+ XGCValues gcv; -+ -+ gcv.foreground = col[ColFG]; -+ XChangeGC(dpy, dc.gc, GCForeground, &gcv); -+ XDrawLine(dpy, dc.drawable, dc.gc, dc.x, dc.y, dc.x, dc.y + (dc.font.ascent + dc.font.descent + 2)); -+} -+ -+void - drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { - int x; - XGCValues gcv; -@@ -1274,8 +1333,7 @@ - } - if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { - updatetitle(c); -- if(c == c->mon->sel) -- drawbar(c->mon); -+ drawbar(c->mon); - } - } - } diff --git a/dwm.suckless.org/patches/fancybar.md b/dwm.suckless.org/patches/fancybar.md @@ -6,16 +6,14 @@ This patch provides a status bar that shows the titles of all visible windows (as opposed to showing just the selected one). When the titles don't completely fit, they're cropped. The title of the selected window is inverted. -[![Fancybar, no cropping][1]][2] [![Fancybar with cropping][3]][4] +[![Fancybar][1]][1] *Fancybar in action* ## Download * [fancybar-5.6.1.diff](historical/fancybar-5.6.1.diff) (dwm 5.6.1) (20090824) - * [fancybar-r1496.diff](fancybar-r1496.diff) (dwm 5.7) (20090922) - * [fancybar-c794a9f5ae5e.patch](fancybar-c794a9f5ae5e.patch) (20120708) - * [dwm-35db6d8-fancybar.diff](dwm-35db6d8-fancybar.diff) (20150105) + * [dwm-6.1-fancybar.diff](dwm-6.1-fancybar.diff) (20151109) ## Author @@ -24,7 +22,4 @@ fit, they're cropped. The title of the selected window is inverted. This patch was inspired by the decorated tabbed layout of Xmonad. -[1]: http://port70.net/~kzed/dwm-5.6.1/dwm-5.6.1-fancybar-1.png.jpg -[2]: http://port70.net/~kzed/dwm-5.6.1/dwm-5.6.1-fancybar-1.png -[3]: http://port70.net/~kzed/dwm-5.6.1/dwm-5.6.1-fancybar-2.png.jpg -[4]: http://port70.net/~kzed/dwm-5.6.1/dwm-5.6.1-fancybar-2.png +[1]: http://s27.postimg.org/nvlkivn03/2015_10_14_132203_727x15_scrot.png diff --git a/dwm.suckless.org/patches/fancybarclickable.md b/dwm.suckless.org/patches/fancybarclickable.md @@ -8,14 +8,17 @@ minus the [statuscolors](statuscolors). It uses the dwm bar to show you the titles of all the windows in the current tag and lets you select windows by selecting their title in the dwm bar. +[![Fancybarclickable][1]][1] + Download -------- * [dwm-6.1-fancybarclickable.diff](dwm-6.1-fancybarclickable.diff) Authors ------- - -* Stefan Mark wrote fancycoloredbarclickable. -* Mate Nagy wrote fancybar. +* Stefan Mark wrote [fancycoloredbarclickable](fancycoloredbarclickable.md). +* Mate Nagy wrote [fancybar](fancybar.md). * An anonymous Canadian updated the fancybar patch and added the - selectby-click-on-title function from fancycoloredbarclickable to it. + `selectby-click-on-title` function from fancycoloredbarclickable to it. + +[1]: http://s4.postimg.org/ql2f934wd/fancybar.png diff --git a/dwm.suckless.org/patches/fibonacci.md b/dwm.suckless.org/patches/fibonacci.md @@ -18,10 +18,6 @@ arrangement can be seen below. +-----------+-----+-----+ +-----------+-----+-----+ spiral dwindle -[![dwm in spiral layout.][1]][2] - -*Links2, sic, xterm & xclock in spiral layout.* - ## Usage 1. Download the patch and apply according to the [general instructions](.). @@ -50,6 +46,4 @@ Joe Thornber's spiral tiling for [Xmonad][3] formed the inspiration for this patch. Thanks to Jan Christoph Ebersbach for updating this patch for versions 4.5 to 4.9. -[1]: http://schot.a-eskwadraat.nl/images/dwm-spiral_small.png -[2]: http://schot.a-eskwadraat.nl/images/dwm-spiral.png -[3]: http://www.xmonad.org +[1]: http://www.xmonad.org diff --git a/dwm.suckless.org/patches/flextile.md b/dwm.suckless.org/patches/flextile.md @@ -8,7 +8,7 @@ This patch replaces the `tile` layout with a more flexible version. The features * left/right/top/bottom n-master, right/left/bottom/top/no stack/deck (deck is like `monocle` in the stack area) * per-tag configuration -It therefor provides i. a. the following additional possibilities: +It therefore provides the following additional possibilities: * `tile` for left-handed people * compare multiple files with one other each at a time without switching between views diff --git a/dwm.suckless.org/patches/focusonclick.md b/dwm.suckless.org/patches/focusonclick.md @@ -7,8 +7,8 @@ ## Download * [dwm-6.0-focusonclick.diff](dwm-6.0-focusonclick.diff) (2012-11-24) - * [dwm-r1508-focusonclick.diff](dwm-r1508-focusonclick.diff) (dwm r1508) (20100321) - * [dwm-5.8.2-focusonclick.diff](dwm-5.8.2-focusonclick.diff) (dwm 2010604) + * [dwm-git-20100321-focusonclick.diff](historical/dwm-git-20100321-focusonclick.diff) + * [dwm-5.8.2-focusonclick.diff](historical/dwm-5.8.2-focusonclick.diff) (dwm 2010604) ## Author diff --git a/dwm.suckless.org/patches/hide_vacant_tags.md b/dwm.suckless.org/patches/hide_vacant_tags.md @@ -18,9 +18,10 @@ filled/empty rectangles. Download -------- -* [dwm-6.1-hide_vacant_tags.diff](dwm-6.1-hide_vacant_tags.diff) (1169b) (20140607) +* [dwm-6.1-hide_vacant_tags.diff](dwm-6.1-hide_vacant_tags.diff) - 2016-01-22 Author ------ * [Ondřej Grover](mailto:ondrej.grover@gmail.com) +* Matthew Boswell - mordervomubel+suckless at lockmail dot us (mechanical update for dwm 6.1 release) diff --git a/dwm.suckless.org/patches/dwm-5.6.1-attachabove.diff b/dwm.suckless.org/patches/historical/dwm-5.6.1-attachabove.diff diff --git a/dwm.suckless.org/patches/dwm-5.6.1-attachaside.diff b/dwm.suckless.org/patches/historical/dwm-5.6.1-attachaside.diff diff --git a/dwm.suckless.org/patches/dwm-5.7.2-attachaside.diff b/dwm.suckless.org/patches/historical/dwm-5.7.2-attachaside.diff diff --git a/dwm.suckless.org/patches/dwm-5.8.2-focusonclick.diff b/dwm.suckless.org/patches/historical/dwm-5.8.2-focusonclick.diff diff --git a/dwm.suckless.org/patches/dwm-5.8.2-pertag.diff b/dwm.suckless.org/patches/historical/dwm-5.8.2-pertag.diff diff --git a/dwm.suckless.org/patches/dwm-5.8.2-pertag_without_bar.diff b/dwm.suckless.org/patches/historical/dwm-5.8.2-pertag_without_bar.diff diff --git a/dwm.suckless.org/patches/historical/dwm-6.0-xft.diff b/dwm.suckless.org/patches/historical/dwm-6.0-xft.diff @@ -0,0 +1,259 @@ +diff --git a/config.def.h b/config.def.h +index 77ff358..a355bf0 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -1,7 +1,7 @@ + /* See LICENSE file for copyright and license details. */ + + /* appearance */ +-static const char font[] = "-*-terminus-medium-r-*-*-16-*-*-*-*-*-*-*"; ++static const char font[] = "monospace-9"; + static const char normbordercolor[] = "#444444"; + static const char normbgcolor[] = "#222222"; + static const char normfgcolor[] = "#bbbbbb"; +diff --git a/config.mk b/config.mk +index 484554a..a09be79 100644 +--- a/config.mk ++++ b/config.mk +@@ -15,8 +15,8 @@ XINERAMALIBS = -L${X11LIB} -lXinerama + XINERAMAFLAGS = -DXINERAMA + + # includes and libs +-INCS = -I. -I/usr/include -I${X11INC} +-LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 ${XINERAMALIBS} ++INCS = -I. -I/usr/include -I${X11INC} -I/usr/include/freetype2 ++LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 ${XINERAMALIBS} -lfontconfig -lXft + + # flags + CPPFLAGS = -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +diff --git a/dwm.c b/dwm.c +index 1d78655..9587e77 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -39,6 +39,7 @@ + #ifdef XINERAMA + #include <X11/extensions/Xinerama.h> + #endif /* XINERAMA */ ++#include <X11/Xft/Xft.h> + + /* macros */ + #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) +@@ -99,16 +100,15 @@ struct Client { + + typedef struct { + int x, y, w, h; +- unsigned long norm[ColLast]; +- unsigned long sel[ColLast]; ++ XftColor norm[ColLast]; ++ XftColor sel[ColLast]; + Drawable drawable; + GC gc; + struct { + int ascent; + int descent; + int height; +- XFontSet set; +- XFontStruct *xfont; ++ XftFont *xfont; + } font; + } DC; /* draw context */ + +@@ -178,15 +178,15 @@ static void die(const char *errstr, ...); + static Monitor *dirtomon(int dir); + static void drawbar(Monitor *m); + static void drawbars(void); +-static void drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]); +-static void drawtext(const char *text, unsigned long col[ColLast], Bool invert); ++static void drawsquare(Bool filled, Bool empty, Bool invert, XftColor col[ColLast]); ++static void drawtext(const char *text, XftColor col[ColLast], Bool invert); + 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 unsigned long getcolor(const char *colstr); ++static XftColor getcolor(const char *colstr); + static Bool getrootptr(int *x, int *y); + static long getstate(Window w); + static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); +@@ -485,10 +485,6 @@ cleanup(void) { + for(m = mons; m; m = m->next) + while(m->stack) + unmanage(m->stack, False); +- if(dc.font.set) +- XFreeFontSet(dpy, dc.font.set); +- else +- XFreeFont(dpy, dc.font.xfont); + XUngrabKey(dpy, AnyKey, AnyModifier, root); + XFreePixmap(dpy, dc.drawable); + XFreeGC(dpy, dc.gc); +@@ -719,7 +715,7 @@ void + drawbar(Monitor *m) { + int x; + unsigned int i, occ = 0, urg = 0; +- unsigned long *col; ++ XftColor *col; + Client *c; + + for(c = m->clients; c; c = c->next) { +@@ -774,10 +770,10 @@ drawbars(void) { + } + + void +-drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { ++drawsquare(Bool filled, Bool empty, Bool invert, XftColor col[ColLast]) { + int x; + +- XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]); ++ XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG].pixel); + x = (dc.font.ascent + dc.font.descent + 2) / 4; + if(filled) + XFillRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x+1, x+1); +@@ -786,11 +782,12 @@ drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { + } + + void +-drawtext(const char *text, unsigned long col[ColLast], Bool invert) { ++drawtext(const char *text, XftColor col[ColLast], Bool invert) { + char buf[256]; + int i, x, y, h, len, olen; ++ XftDraw *d; + +- XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]); ++ XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG].pixel); + XFillRectangle(dpy, dc.drawable, dc.gc, dc.x, dc.y, dc.w, dc.h); + if(!text) + return; +@@ -805,11 +802,11 @@ drawtext(const char *text, unsigned long col[ColLast], Bool invert) { + memcpy(buf, text, len); + if(len < olen) + for(i = len; i && i > len - 3; buf[--i] = '.'); +- XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]); +- if(dc.font.set) +- XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len); +- else +- XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); ++ ++ d = XftDrawCreate(dpy, dc.drawable, DefaultVisual(dpy, screen), DefaultColormap(dpy,screen)); ++ ++ XftDrawStringUtf8(d, &col[invert ? ColBG : ColFG], dc.font.xfont, x, y, (XftChar8 *) buf, len); ++ XftDrawDestroy(d); + } + + void +@@ -855,7 +852,7 @@ focus(Client *c) { + detachstack(c); + attachstack(c); + grabbuttons(c, True); +- XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]); ++ XSetWindowBorder(dpy, c->win, dc.sel[ColBorder].pixel); + setfocus(c); + } + else +@@ -926,14 +923,14 @@ getatomprop(Client *c, Atom prop) { + return atom; + } + +-unsigned long ++XftColor + getcolor(const char *colstr) { +- Colormap cmap = DefaultColormap(dpy, screen); +- XColor color; ++ XftColor color; + +- if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color)) ++ if(!XftColorAllocName(dpy, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen), colstr, &color)) + die("error, cannot allocate color '%s'\n", colstr); +- return color.pixel; ++ ++ return color; + } + + Bool +@@ -1034,35 +1031,13 @@ incnmaster(const Arg *arg) { + + void + initfont(const char *fontstr) { +- char *def, **missing; +- int n; + +- dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); +- if(missing) { +- while(n--) +- fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]); +- XFreeStringList(missing); +- } +- if(dc.font.set) { +- XFontStruct **xfonts; +- char **font_names; +- +- dc.font.ascent = dc.font.descent = 0; +- XExtentsOfFontSet(dc.font.set); +- n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); +- while(n--) { +- dc.font.ascent = MAX(dc.font.ascent, (*xfonts)->ascent); +- dc.font.descent = MAX(dc.font.descent,(*xfonts)->descent); +- xfonts++; +- } +- } +- else { +- if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)) +- && !(dc.font.xfont = XLoadQueryFont(dpy, "fixed"))) +- die("error, cannot load font: '%s'\n", fontstr); +- dc.font.ascent = dc.font.xfont->ascent; +- dc.font.descent = dc.font.xfont->descent; +- } ++ if(!(dc.font.xfont = XftFontOpenName(dpy,screen,fontstr)) ++ && !(dc.font.xfont = XftFontOpenName(dpy,screen,"fixed"))) ++ die("error, cannot load font: '%s'\n", fontstr); ++ ++ dc.font.ascent = dc.font.xfont->ascent; ++ dc.font.descent = dc.font.xfont->descent; + dc.font.height = dc.font.ascent + dc.font.descent; + } + +@@ -1144,7 +1119,7 @@ manage(Window w, XWindowAttributes *wa) { + + wc.border_width = c->bw; + XConfigureWindow(dpy, w, CWBorderWidth, &wc); +- XSetWindowBorder(dpy, w, dc.norm[ColBorder]); ++ XSetWindowBorder(dpy, w, dc.norm[ColBorder].pixel); + configure(c); /* propagates border_width, if size doesn't change */ + updatewindowtype(c); + updatesizehints(c); +@@ -1621,8 +1596,6 @@ setup(void) { + dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), bh, DefaultDepth(dpy, screen)); + dc.gc = XCreateGC(dpy, root, 0, NULL); + XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); +- if(!dc.font.set) +- XSetFont(dpy, dc.gc, dc.font.xfont->fid); + /* init bars */ + updatebars(); + updatestatus(); +@@ -1692,13 +1665,9 @@ tagmon(const Arg *arg) { + + int + textnw(const char *text, unsigned int len) { +- XRectangle r; +- +- if(dc.font.set) { +- XmbTextExtents(dc.font.set, text, len, NULL, &r); +- return r.width; +- } +- return XTextWidth(dc.font.xfont, text, len); ++ XGlyphInfo ext; ++ XftTextExtentsUtf8(dpy, dc.font.xfont, (XftChar8 *) text, len, &ext); ++ return ext.xOff; + } + + void +@@ -1776,7 +1745,7 @@ unfocus(Client *c, Bool setfocus) { + if(!c) + return; + grabbuttons(c, False); +- XSetWindowBorder(dpy, c->win, dc.norm[ColBorder]); ++ XSetWindowBorder(dpy, c->win, dc.norm[ColBorder].pixel); + if(setfocus) + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + } diff --git a/dwm.suckless.org/patches/dwm-6.1-xft-with-fallback-font.diff b/dwm.suckless.org/patches/historical/dwm-6.1-xft-with-fallback-font.diff diff --git a/dwm.suckless.org/patches/dwm-cdec978-center.diff b/dwm.suckless.org/patches/historical/dwm-cdec978-center.diff diff --git a/dwm.suckless.org/patches/dwm-r1508-focusonclick.diff b/dwm.suckless.org/patches/historical/dwm-git-20100321-focusonclick.diff diff --git a/dwm.suckless.org/patches/historical/dwm-master_2015-10-20_7e1182c-pertag-tab-v2b.diff b/dwm.suckless.org/patches/historical/dwm-master_2015-10-20_7e1182c-pertag-tab-v2b.diff @@ -0,0 +1,692 @@ +diff --git a/config.def.h b/config.def.h +index 3fde3cf..ef6d4d3 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -15,10 +15,22 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const Bool showbar = True; /* False means no bar */ + static const Bool topbar = True; /* False means bottom bar */ ++/* Display modes of the tab bar: never shown, always shown, shown only in */ ++/* monocle mode in presence of several windows. */ ++/* Modes after showtab_nmodes are disabled */ ++enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always}; ++static const int showtab = showtab_auto; /* Default tab bar show mode */ ++static const Bool toptab = False; /* False means bottom tab bar */ ++ + + /* tagging */ + static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + ++/* default layout per tags */ ++/* The first element is for all-tag view, following i-th element corresponds to */ ++/* tags[i]. Layout is referred using the layouts array index.*/ ++static int def_layouts[1 + LENGTH(tags)] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; ++ + static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class +@@ -32,7 +44,7 @@ static const Rule rules[] = { + /* layout(s) */ + static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ + static const int nmaster = 1; /* number of clients in master area */ +-static const Bool resizehints = True; /* True means respect size hints in tiled resizals */ ++static const Bool resizehints = False; /* True means respect size hints in tiled resizals */ + + static const Layout layouts[] = { + /* symbol arrange function */ +@@ -62,6 +74,7 @@ static Key keys[] = { + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, + { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_b, togglebar, {0} }, ++ { MODKEY, XK_w, tabmode, {-1} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, +@@ -109,5 +122,6 @@ static Button buttons[] = { + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, ++ { ClkTabBar, 0, Button1, focuswin, {0} }, + }; + +diff --git a/dwm.1 b/dwm.1 +index 6687011..077d92b 100644 +--- a/dwm.1 ++++ b/dwm.1 +@@ -19,14 +19,22 @@ layout applied. + 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. ++Each screen contains two small status bars. ++.P ++One bar 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 ++Another bar contains a tab for each window of the current view and allows ++navigation between windows, especially in the monocle mode. The different ++display modes of this bar are described under the Mod1\-w Keybord command ++section. When a single tag is selected, that tag is indicated in the left corner ++of the tab bar. + .P + dwm draws a small border around windows to indicate the focus state. + .SH OPTIONS +@@ -43,7 +51,8 @@ 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. ++label toggles between tiled and floating layout, click on a window name in the ++tab bar brings focus to that window. + .TP + .B Button3 + click on a tag label adds/removes all windows with that tag to/from the view. +@@ -104,6 +113,12 @@ Increase master area size. + .B Mod1\-h + Decrease master area size. + .TP ++.B Mod1\-w ++Cycle over the tab bar display modes: never displayed, always displayed, ++displayed only in monocle mode when the view contains than one window (auto ++mode). Some display modes can be disabled in the configuration, config.h. In ++the default configuration only "never" and "auto" display modes are enabled. ++.TP + .B Mod1\-Return + Zooms/cycles focused window to/from master area (tiled layouts only). + .TP +diff --git a/dwm.c b/dwm.c +index 96b43f7..c0aab5d 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -64,7 +64,7 @@ enum { NetSupported, NetWMName, NetWMState, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ +-enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ++enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ + + typedef union { +@@ -111,25 +111,35 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++#define MAXTABS 50 ++ ++typedef struct Pertag Pertag; + struct Monitor { + char ltsymbol[16]; + float mfact; + int nmaster; + int num; + int by; /* bar geometry */ ++ int ty; /* tab bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; + Bool showbar; ++ Bool showtab; + Bool topbar; ++ Bool toptab; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; ++ Window tabwin; ++ int ntabs; ++ int tab_widths[MAXTABS]; + const Layout *lt[2]; ++ Pertag *pertag; + }; + + typedef struct { +@@ -164,12 +174,15 @@ static void detachstack(Client *c); + static Monitor *dirtomon(int dir); + static void drawbar(Monitor *m); + static void drawbars(void); ++static void drawtab(Monitor *m); ++static void drawtabs(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 void focuswin(const Arg* arg); + static Bool getrootptr(int *x, int *y); + static long getstate(Window w); + static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); +@@ -206,6 +219,7 @@ static void setup(void); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static void tabmode(const Arg *arg); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *); +@@ -240,6 +254,7 @@ 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 th = 0; /* tab bar geometry */ + static int (*xerrorxlib)(Display *, XErrorEvent *); + static unsigned int numlockmask = 0; + static void (*handler[LASTEvent]) (XEvent *) = { +@@ -270,6 +285,16 @@ static Window root; + /* configuration, allows nested code to access above variables */ + #include "config.h" + ++struct Pertag { ++ unsigned int curtag, prevtag; /* current and previous tag */ ++ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ ++ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ ++ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ ++ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ ++ Bool showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ ++ Client *prevzooms[LENGTH(tags) + 1]; /* store zoom information */ ++}; ++ + /* compile-time check if all tags fit into an unsigned int bit array. */ + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +@@ -389,6 +414,9 @@ arrange(Monitor *m) { + + void + arrangemon(Monitor *m) { ++ updatebarpos(m); ++ XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th); ++ + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); + if(m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); +@@ -437,14 +465,32 @@ buttonpress(XEvent *e) { + else + click = ClkWinTitle; + } ++ if(ev->window == selmon->tabwin) { ++ i = 0; x = 0; ++ for(c = selmon->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ x += selmon->tab_widths[i]; ++ if (ev->x > x) ++ ++i; ++ else ++ break; ++ if(i >= m->ntabs) break; ++ } ++ if(c) { ++ click = ClkTabBar; ++ arg.ui = i; ++ } ++ } + else if((c = wintoclient(ev->window))) { + focus(c); + 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); ++ && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)){ ++ buttons[i].func(((click == ClkTagBar || click == ClkTabBar) ++ && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg); ++ } + } + + void +@@ -497,6 +543,8 @@ cleanupmon(Monitor *mon) { + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); ++ XUnmapWindow(dpy, mon->tabwin); ++ XDestroyWindow(dpy, mon->tabwin); + free(mon); + } + +@@ -516,6 +564,7 @@ void + clientmessage(XEvent *e) { + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); ++ int i; + + if(!c) + return; +@@ -528,6 +577,8 @@ clientmessage(XEvent *e) { + if(!ISVISIBLE(c)) { + c->mon->seltags ^= 1; + c->mon->tagset[c->mon->seltags] = c->tags; ++ for(i=0; !(c->tags & 1 << i); i++); ++ view(&(Arg){.ui = 1 << i}); + } + pop(c); + } +@@ -565,8 +616,11 @@ configurenotify(XEvent *e) { + if(updategeom() || dirty) { + drw_resize(drw, sw, bh); + updatebars(); +- for(m = mons; m; m = m->next) ++ //refreshing display of status bar. The tab bar is handled by the arrange() ++ //method, which is called below ++ for(m = mons; m; m = m->next){ + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); ++ } + focus(NULL); + arrange(NULL); + } +@@ -629,16 +683,41 @@ configurerequest(XEvent *e) { + Monitor * + createmon(void) { + Monitor *m; ++ int i; + + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; + m->mfact = mfact; + m->nmaster = nmaster; + m->showbar = showbar; ++ m->showtab = showtab; + m->topbar = topbar; +- m->lt[0] = &layouts[0]; ++ m->toptab = toptab; ++ m->ntabs = 0; ++ m->lt[0] = &layouts[def_layouts[1] % LENGTH(layouts)]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); ++ if(!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Pertag)); ++ m->pertag->curtag = m->pertag->prevtag = 1; ++ for(i=0; i <= LENGTH(tags); i++) { ++ /* init nmaster */ ++ m->pertag->nmasters[i] = m->nmaster; ++ ++ /* init mfacts */ ++ m->pertag->mfacts[i] = m->mfact; ++ ++ /* init layouts */ ++ m->pertag->ltidxs[i][0] = &layouts[def_layouts[i % LENGTH(def_layouts)] % LENGTH(layouts)]; ++ m->pertag->ltidxs[i][1] = m->lt[1]; ++ m->pertag->sellts[i] = m->sellt; ++ ++ /* init showbar */ ++ m->pertag->showbars[i] = m->showbar; ++ ++ /* swap focus and zoomswap*/ ++ m->pertag->prevzooms[i] = NULL; ++ } + return m; + } + +@@ -749,6 +828,104 @@ drawbars(void) { + } + + void ++drawtabs(void) { ++ Monitor *m; ++ ++ for(m = mons; m; m = m->next) ++ drawtab(m); ++} ++ ++static int ++cmpint(const void *p1, const void *p2) { ++ /* The actual arguments to this function are "pointers to ++ pointers to char", but strcmp(3) arguments are "pointers ++ to char", hence the following cast plus dereference */ ++ return *((int*) p1) > * (int*) p2; ++} ++ ++ ++void ++drawtab(Monitor *m) { ++ Client *c; ++ int i; ++ int itag = -1; ++ char view_info[50]; ++ int view_info_w = 0; ++ int sorted_label_widths[MAXTABS]; ++ int tot_width; ++ int maxsize = bh; ++ int x = 0; ++ int w = 0; ++ ++ //view_info: indicate the tag which is displayed in the view ++ for(i = 0; i < LENGTH(tags); ++i){ ++ if((selmon->tagset[selmon->seltags] >> i) & 1) { ++ if(itag >=0){ //more than one tag selected ++ itag = -1; ++ break; ++ } ++ itag = i; ++ } ++ } ++ if(0 <= itag && itag < LENGTH(tags)){ ++ snprintf(view_info, sizeof view_info, "[%s]", tags[itag]); ++ } else { ++ strncpy(view_info, "[...]", sizeof view_info); ++ } ++ view_info[sizeof(view_info) - 1 ] = 0; ++ view_info_w = TEXTW(view_info); ++ tot_width = view_info_w; ++ ++ /* Calculates number of labels and their width */ ++ m->ntabs = 0; ++ for(c = m->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ m->tab_widths[m->ntabs] = TEXTW(c->name); ++ tot_width += m->tab_widths[m->ntabs]; ++ ++m->ntabs; ++ if(m->ntabs >= MAXTABS) break; ++ } ++ ++ if(tot_width > m->ww){ //not enough space to display the labels, they need to be truncated ++ memcpy(sorted_label_widths, m->tab_widths, sizeof(int) * m->ntabs); ++ qsort(sorted_label_widths, m->ntabs, sizeof(int), cmpint); ++ tot_width = view_info_w; ++ for(i = 0; i < m->ntabs; ++i){ ++ if(tot_width + (m->ntabs - i) * sorted_label_widths[i] > m->ww) ++ break; ++ tot_width += sorted_label_widths[i]; ++ } ++ maxsize = (m->ww - tot_width) / (m->ntabs - i); ++ } else{ ++ maxsize = m->ww; ++ } ++ i = 0; ++ for(c = m->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ if(i >= m->ntabs) break; ++ if(m->tab_widths[i] > maxsize) m->tab_widths[i] = maxsize; ++ w = m->tab_widths[i]; ++ drw_setscheme(drw, (c == m->sel) ? &scheme[SchemeSel] : &scheme[SchemeNorm]); ++ drw_text(drw, x, 0, w, th, c->name, 0); ++ x += w; ++ ++i; ++ } ++ ++ drw_setscheme(drw, &scheme[SchemeNorm]); ++ ++ /* cleans interspace between window names and current viewed tag label */ ++ w = m->ww - view_info_w - x; ++ drw_text(drw, x, 0, w, th, NULL, 0); ++ ++ /* view info */ ++ x += w; ++ w = view_info_w; ++ drw_text(drw, x, 0, w, th, view_info, 0); ++ ++ drw_map(drw, m->tabwin, 0, 0, m->ww, th); ++} ++ ++void + enternotify(XEvent *e) { + Client *c; + Monitor *m; +@@ -772,8 +949,10 @@ 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); ++ drawtab(m); ++ } + } + + void +@@ -800,6 +979,7 @@ focus(Client *c) { + } + selmon->sel = c; + drawbars(); ++ drawtabs(); + } + + void +@@ -850,6 +1030,19 @@ focusstack(const Arg *arg) { + } + } + ++void ++focuswin(const Arg* arg){ ++ int iwin = arg->i; ++ Client* c = NULL; ++ for(c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next){ ++ if(ISVISIBLE(c)) --iwin; ++ }; ++ if(c) { ++ focus(c); ++ restack(selmon); ++ } ++} ++ + Atom + getatomprop(Client *c, Atom prop) { + int di; +@@ -957,7 +1150,7 @@ grabkeys(void) { + + void + incnmaster(const Arg *arg) { +- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); + } + +@@ -1215,12 +1408,14 @@ propertynotify(XEvent *e) { + case XA_WM_HINTS: + updatewmhints(c); + drawbars(); ++ drawtabs(); + break; + } + if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { + updatetitle(c); + if(c == c->mon->sel) + drawbar(c->mon); ++ drawtab(c->mon); + } + if(ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); +@@ -1328,6 +1523,7 @@ restack(Monitor *m) { + XWindowChanges wc; + + drawbar(m); ++ drawtab(m); + if(!m->sel) + return; + if(m->sel->isfloating || !m->lt[m->sellt]->arrange) +@@ -1469,10 +1665,13 @@ setfullscreen(Client *c, Bool fullscreen) { + + void + setlayout(const Arg *arg) { +- if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) +- selmon->sellt ^= 1; ++ if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) { ++ selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ } + if(arg && arg->v) +- selmon->lt[selmon->sellt] = (Layout *)arg->v; ++ selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if(selmon->sel) + arrange(selmon); +@@ -1490,7 +1689,7 @@ setmfact(const Arg *arg) { + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if(f < 0.1 || f > 0.9) + return; +- selmon->mfact = f; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; + arrange(selmon); + } + +@@ -1511,6 +1710,8 @@ setup(void) { + if (!drw->fontcount) + die("no fonts could be loaded.\n"); + bh = drw->fonts[0]->h + 2; ++ th = bh; ++ + updategeom(); + /* init atoms */ + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); +@@ -1635,13 +1836,23 @@ tile(Monitor *m) { + + void + togglebar(const Arg *arg) { +- selmon->showbar = !selmon->showbar; ++ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; + updatebarpos(selmon); + XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); + arrange(selmon); + } + + void ++tabmode(const Arg *arg) { ++ if(arg && arg->i >= 0) ++ selmon->showtab = arg->ui % showtab_nmodes; ++ else ++ selmon->showtab = (selmon->showtab + 1 ) % showtab_nmodes; ++ arrange(selmon); ++} ++ ++ ++void + togglefloating(const Arg *arg) { + if(!selmon->sel) + return; +@@ -1671,9 +1882,29 @@ toggletag(const Arg *arg) { + void + toggleview(const Arg *arg) { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); ++ int i; + + if(newtagset) { ++ if(newtagset == ~0) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = 0; ++ } ++ /* test if the user did not select the same tag */ ++ if(!(newtagset & 1 << (selmon->pertag->curtag - 1))) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ for (i=0; !(newtagset & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } + selmon->tagset[selmon->seltags] = newtagset; ++ ++ /* apply settings for this view */ ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); + focus(NULL); + arrange(selmon); + } +@@ -1745,20 +1976,43 @@ updatebars(void) { + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); + XMapRaised(dpy, m->barwin); ++ m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen), ++ CopyFromParent, DefaultVisual(dpy, screen), ++ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); ++ XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor); ++ XMapRaised(dpy, m->tabwin); + } + } + + void + updatebarpos(Monitor *m) { ++ Client *c; ++ int nvis = 0; ++ + 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 ++ if ( m->topbar ) ++ m->wy += bh; ++ } else { + m->by = -bh; ++ } ++ ++ for(c = m->clients; c; c = c->next){ ++ if(ISVISIBLE(c)) ++nvis; ++ } ++ ++ if(m->showtab == showtab_always ++ || ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->sellt]->arrange == monocle))){ ++ m->wh -= th; ++ m->ty = m->toptab ? m->wy : m->wy + m->wh; ++ if ( m->toptab ) ++ m->wy += th; ++ } else { ++ m->ty = -th; ++ } + } + + void +@@ -1967,11 +2221,33 @@ updatewmhints(Client *c) { + + void + view(const Arg *arg) { ++ int i; ++ unsigned int tmptag; ++ + if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ +- if(arg->ui & TAGMASK) ++ if(arg->ui & TAGMASK) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; ++ if(arg->ui == ~0) ++ selmon->pertag->curtag = 0; ++ else { ++ for (i=0; !(arg->ui & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } ++ } else { ++ tmptag = selmon->pertag->prevtag; ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = tmptag; ++ } ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); + focus(NULL); + arrange(selmon); + } +@@ -1997,7 +2273,7 @@ wintomon(Window w) { + if(w == root && getrootptr(&x, &y)) + return recttomon(x, y, 1, 1); + for(m = mons; m; m = m->next) +- if(w == m->barwin) ++ if(w == m->barwin || w == m->tabwin) + return m; + if((c = wintoclient(w))) + return c->mon; diff --git a/dwm.suckless.org/patches/historical/dwm-master_2015-10-20_7e1182c-tab-v2b.diff b/dwm.suckless.org/patches/historical/dwm-master_2015-10-20_7e1182c-tab-v2b.diff @@ -0,0 +1,506 @@ +diff --git a/config.def.h b/config.def.h +index 3fde3cf..6a7ad0f 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -15,6 +15,13 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const Bool showbar = True; /* False means no bar */ + static const Bool topbar = True; /* False means bottom bar */ ++/* Display modes of the tab bar: never shown, always shown, shown only in */ ++/* monocle mode in presence of several windows. */ ++/* Modes after showtab_nmodes are disabled */ ++enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always}; ++static const int showtab = showtab_auto; /* Default tab bar show mode */ ++static const Bool toptab = False; /* False means bottom tab bar */ ++ + + /* tagging */ + static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; +@@ -32,7 +39,7 @@ static const Rule rules[] = { + /* layout(s) */ + static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ + static const int nmaster = 1; /* number of clients in master area */ +-static const Bool resizehints = True; /* True means respect size hints in tiled resizals */ ++static const Bool resizehints = False; /* True means respect size hints in tiled resizals */ + + static const Layout layouts[] = { + /* symbol arrange function */ +@@ -62,6 +69,7 @@ static Key keys[] = { + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, + { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_b, togglebar, {0} }, ++ { MODKEY, XK_w, tabmode, {-1} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, +@@ -109,5 +117,6 @@ static Button buttons[] = { + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, ++ { ClkTabBar, 0, Button1, focuswin, {0} }, + }; + +diff --git a/dwm.1 b/dwm.1 +index 6687011..f736591 100644 +--- a/dwm.1 ++++ b/dwm.1 +@@ -19,14 +19,22 @@ layout applied. + 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. ++Each screen contains two small status bars. ++.P ++One bar 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 ++Another bar contains a tab for each window of the current view and allows ++navigation between windows, especially in the monocle mode. The different ++display modes of this bar are described under the Mod1\-w Keybord command ++section. When a single tag is selected, that tag is indicated in the left ++corner of the tab bar. + .P + dwm draws a small border around windows to indicate the focus state. + .SH OPTIONS +@@ -43,7 +51,8 @@ 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. ++label toggles between tiled and floating layout, click on a window name in the ++tab bar brings focus to that window. + .TP + .B Button3 + click on a tag label adds/removes all windows with that tag to/from the view. +@@ -104,6 +113,12 @@ Increase master area size. + .B Mod1\-h + Decrease master area size. + .TP ++.B Mod1\-w ++Cycle over the tab bar display modes: never displayed, always displayed, ++displayed only in monocle mode when the view contains than one window (auto ++mode). Some display modes can be disabled in the configuration, config.h. In ++the default configuration only "never" and "auto" display modes are enabled. ++.TP + .B Mod1\-Return + Zooms/cycles focused window to/from master area (tiled layouts only). + .TP +diff --git a/dwm.c b/dwm.c +index 96b43f7..585dd7b 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -64,7 +64,7 @@ enum { NetSupported, NetWMName, NetWMState, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ +-enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ++enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ + + typedef union { +@@ -111,24 +111,32 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++#define MAXTABS 50 ++ + struct Monitor { + char ltsymbol[16]; + float mfact; + int nmaster; + int num; + int by; /* bar geometry */ ++ int ty; /* tab bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; + Bool showbar; ++ Bool showtab; + Bool topbar; ++ Bool toptab; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; ++ Window tabwin; ++ int ntabs; ++ int tab_widths[MAXTABS]; + const Layout *lt[2]; + }; + +@@ -164,12 +172,15 @@ static void detachstack(Client *c); + static Monitor *dirtomon(int dir); + static void drawbar(Monitor *m); + static void drawbars(void); ++static void drawtab(Monitor *m); ++static void drawtabs(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 void focuswin(const Arg* arg); + static Bool getrootptr(int *x, int *y); + static long getstate(Window w); + static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); +@@ -206,6 +217,7 @@ static void setup(void); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static void tabmode(const Arg *arg); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *); +@@ -240,6 +252,7 @@ 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 th = 0; /* tab bar geometry */ + static int (*xerrorxlib)(Display *, XErrorEvent *); + static unsigned int numlockmask = 0; + static void (*handler[LASTEvent]) (XEvent *) = { +@@ -389,6 +402,9 @@ arrange(Monitor *m) { + + void + arrangemon(Monitor *m) { ++ updatebarpos(m); ++ XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th); ++ + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); + if(m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); +@@ -437,14 +453,32 @@ buttonpress(XEvent *e) { + else + click = ClkWinTitle; + } ++ if(ev->window == selmon->tabwin) { ++ i = 0; x = 0; ++ for(c = selmon->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ x += selmon->tab_widths[i]; ++ if (ev->x > x) ++ ++i; ++ else ++ break; ++ if(i >= m->ntabs) break; ++ } ++ if(c) { ++ click = ClkTabBar; ++ arg.ui = i; ++ } ++ } + else if((c = wintoclient(ev->window))) { + focus(c); + 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); ++ && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)){ ++ buttons[i].func(((click == ClkTagBar || click == ClkTabBar) ++ && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg); ++ } + } + + void +@@ -497,6 +531,8 @@ cleanupmon(Monitor *mon) { + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); ++ XUnmapWindow(dpy, mon->tabwin); ++ XDestroyWindow(dpy, mon->tabwin); + free(mon); + } + +@@ -565,8 +601,11 @@ configurenotify(XEvent *e) { + if(updategeom() || dirty) { + drw_resize(drw, sw, bh); + updatebars(); +- for(m = mons; m; m = m->next) ++ //refreshing display of status bar. The tab bar is handled by the arrange() ++ //method, which is called below ++ for(m = mons; m; m = m->next){ + XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); ++ } + focus(NULL); + arrange(NULL); + } +@@ -635,7 +674,10 @@ createmon(void) { + m->mfact = mfact; + m->nmaster = nmaster; + m->showbar = showbar; ++ m->showtab = showtab; + m->topbar = topbar; ++ m->toptab = toptab; ++ m->ntabs = 0; + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); +@@ -749,6 +791,104 @@ drawbars(void) { + } + + void ++drawtabs(void) { ++ Monitor *m; ++ ++ for(m = mons; m; m = m->next) ++ drawtab(m); ++} ++ ++static int ++cmpint(const void *p1, const void *p2) { ++ /* The actual arguments to this function are "pointers to ++ pointers to char", but strcmp(3) arguments are "pointers ++ to char", hence the following cast plus dereference */ ++ return *((int*) p1) > * (int*) p2; ++} ++ ++ ++void ++drawtab(Monitor *m) { ++ Client *c; ++ int i; ++ int itag = -1; ++ char view_info[50]; ++ int view_info_w = 0; ++ int sorted_label_widths[MAXTABS]; ++ int tot_width; ++ int maxsize = bh; ++ int x = 0; ++ int w = 0; ++ ++ //view_info: indicate the tag which is displayed in the view ++ for(i = 0; i < LENGTH(tags); ++i){ ++ if((selmon->tagset[selmon->seltags] >> i) & 1) { ++ if(itag >=0){ //more than one tag selected ++ itag = -1; ++ break; ++ } ++ itag = i; ++ } ++ } ++ if(0 <= itag && itag < LENGTH(tags)){ ++ snprintf(view_info, sizeof view_info, "[%s]", tags[itag]); ++ } else { ++ strncpy(view_info, "[...]", sizeof view_info); ++ } ++ view_info[sizeof(view_info) - 1 ] = 0; ++ view_info_w = TEXTW(view_info); ++ tot_width = view_info_w; ++ ++ /* Calculates number of labels and their width */ ++ m->ntabs = 0; ++ for(c = m->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ m->tab_widths[m->ntabs] = TEXTW(c->name); ++ tot_width += m->tab_widths[m->ntabs]; ++ ++m->ntabs; ++ if(m->ntabs >= MAXTABS) break; ++ } ++ ++ if(tot_width > m->ww){ //not enough space to display the labels, they need to be truncated ++ memcpy(sorted_label_widths, m->tab_widths, sizeof(int) * m->ntabs); ++ qsort(sorted_label_widths, m->ntabs, sizeof(int), cmpint); ++ tot_width = view_info_w; ++ for(i = 0; i < m->ntabs; ++i){ ++ if(tot_width + (m->ntabs - i) * sorted_label_widths[i] > m->ww) ++ break; ++ tot_width += sorted_label_widths[i]; ++ } ++ maxsize = (m->ww - tot_width) / (m->ntabs - i); ++ } else{ ++ maxsize = m->ww; ++ } ++ i = 0; ++ for(c = m->clients; c; c = c->next){ ++ if(!ISVISIBLE(c)) continue; ++ if(i >= m->ntabs) break; ++ if(m->tab_widths[i] > maxsize) m->tab_widths[i] = maxsize; ++ w = m->tab_widths[i]; ++ drw_setscheme(drw, (c == m->sel) ? &scheme[SchemeSel] : &scheme[SchemeNorm]); ++ drw_text(drw, x, 0, w, th, c->name, 0); ++ x += w; ++ ++i; ++ } ++ ++ drw_setscheme(drw, &scheme[SchemeNorm]); ++ ++ /* cleans interspace between window names and current viewed tag label */ ++ w = m->ww - view_info_w - x; ++ drw_text(drw, x, 0, w, th, NULL, 0); ++ ++ /* view info */ ++ x += w; ++ w = view_info_w; ++ drw_text(drw, x, 0, w, th, view_info, 0); ++ ++ drw_map(drw, m->tabwin, 0, 0, m->ww, th); ++} ++ ++void + enternotify(XEvent *e) { + Client *c; + Monitor *m; +@@ -772,8 +912,10 @@ 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); ++ drawtab(m); ++ } + } + + void +@@ -800,6 +942,7 @@ focus(Client *c) { + } + selmon->sel = c; + drawbars(); ++ drawtabs(); + } + + void +@@ -850,6 +993,19 @@ focusstack(const Arg *arg) { + } + } + ++void ++focuswin(const Arg* arg){ ++ int iwin = arg->i; ++ Client* c = NULL; ++ for(c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next){ ++ if(ISVISIBLE(c)) --iwin; ++ }; ++ if(c) { ++ focus(c); ++ restack(selmon); ++ } ++} ++ + Atom + getatomprop(Client *c, Atom prop) { + int di; +@@ -1215,12 +1371,14 @@ propertynotify(XEvent *e) { + case XA_WM_HINTS: + updatewmhints(c); + drawbars(); ++ drawtabs(); + break; + } + if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { + updatetitle(c); + if(c == c->mon->sel) + drawbar(c->mon); ++ drawtab(c->mon); + } + if(ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); +@@ -1328,6 +1486,7 @@ restack(Monitor *m) { + XWindowChanges wc; + + drawbar(m); ++ drawtab(m); + if(!m->sel) + return; + if(m->sel->isfloating || !m->lt[m->sellt]->arrange) +@@ -1511,6 +1670,8 @@ setup(void) { + if (!drw->fontcount) + die("no fonts could be loaded.\n"); + bh = drw->fonts[0]->h + 2; ++ th = bh; ++ + updategeom(); + /* init atoms */ + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); +@@ -1642,6 +1803,16 @@ togglebar(const Arg *arg) { + } + + void ++tabmode(const Arg *arg) { ++ if(arg && arg->i >= 0) ++ selmon->showtab = arg->ui % showtab_nmodes; ++ else ++ selmon->showtab = (selmon->showtab + 1 ) % showtab_nmodes; ++ arrange(selmon); ++} ++ ++ ++void + togglefloating(const Arg *arg) { + if(!selmon->sel) + return; +@@ -1745,20 +1916,43 @@ updatebars(void) { + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); + XMapRaised(dpy, m->barwin); ++ m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen), ++ CopyFromParent, DefaultVisual(dpy, screen), ++ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); ++ XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor); ++ XMapRaised(dpy, m->tabwin); + } + } + + void + updatebarpos(Monitor *m) { ++ Client *c; ++ int nvis = 0; ++ + 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 ++ if ( m->topbar ) ++ m->wy += bh; ++ } else { + m->by = -bh; ++ } ++ ++ for(c = m->clients; c; c = c->next){ ++ if(ISVISIBLE(c)) ++nvis; ++ } ++ ++ if(m->showtab == showtab_always ++ || ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->sellt]->arrange == monocle))){ ++ m->wh -= th; ++ m->ty = m->toptab ? m->wy : m->wy + m->wh; ++ if ( m->toptab ) ++ m->wy += th; ++ } else { ++ m->ty = -th; ++ } + } + + void +@@ -1997,7 +2191,7 @@ wintomon(Window w) { + if(w == root && getrootptr(&x, &y)) + return recttomon(x, y, 1, 1); + for(m = mons; m; m = m->next) +- if(w == m->barwin) ++ if(w == m->barwin || w == m->tabwin) + return m; + if((c = wintoclient(w))) + return c->mon; diff --git a/dwm.suckless.org/patches/historical/dwm-r1525-warp.diff b/dwm.suckless.org/patches/historical/dwm-r1525-warp.diff @@ -1,99 +0,0 @@ -diff -r c361034c5a1c dwm.c ---- a/dwm.c Sat Sep 11 19:00:18 2010 +0000 -+++ b/dwm.c Sat Sep 11 21:47:56 2010 +0200 -@@ -236,6 +236,7 @@ - static void updatetitle(Client *c); - static void updatewmhints(Client *c); - static void view(const Arg *arg); -+static void warp(const Client *c); - static Client *wintoclient(Window w); - static Monitor *wintomon(Window w); - static int xerror(Display *dpy, XErrorEvent *ee); -@@ -274,6 +275,7 @@ - static DC dc; - static Monitor *mons = NULL, *selmon = NULL; - static Window root; -+static Bool warpmouse = True; - - /* configuration, allows nested code to access above variables */ - #include "config.h" -@@ -452,10 +454,12 @@ - focus(c); - click = ClkClientWin; - } -+ warpmouse = False; - 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); -+ warpmouse = True; - } - - void -@@ -854,6 +858,7 @@ - unfocus(selmon->sel, True); - selmon = m; - focus(NULL); -+ warp(selmon->sel); - } - - void -@@ -879,6 +884,7 @@ - if(c) { - focus(c); - restack(selmon); -+ warp(c); - } - } - -@@ -1150,6 +1156,7 @@ - XMapWindow(dpy, c->win); - setclientstate(c, NormalState); - arrange(c->mon); -+ warp(c); - } - - void -@@ -1609,6 +1616,7 @@ - if(selmon->sel && arg->ui & TAGMASK) { - selmon->sel->tags = arg->ui & TAGMASK; - arrange(selmon); -+ warp(selmon->sel); - } - } - -@@ -1689,6 +1697,7 @@ - if(newtags) { - selmon->sel->tags = newtags; - arrange(selmon); -+ warp(selmon->sel); - } - } - -@@ -1962,6 +1971,26 @@ - arrange(selmon); - } - -+void -+warp(const Client *c) { -+ Window dummy; -+ int x, y, di; -+ unsigned int dui; -+ -+ if(!c || !warpmouse) -+ return; -+ XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui); -+ if(x > c->x && y > c->y && x < c->y + c->w && y < c->y + c->h) -+ return; -+ XSelectInput(dpy, root, SubstructureRedirectMask -+ & EnterWindowMask); -+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, -+ c->w / 2, c->h / 2); -+ XSelectInput(dpy, root, SubstructureRedirectMask | SubstructureNotifyMask -+ | EnterWindowMask | LeaveWindowMask | StructureNotifyMask); -+} -+ -+ - Client * - wintoclient(Window w) { - Client *c; diff --git a/dwm.suckless.org/patches/dwm-r1578-pertag.diff b/dwm.suckless.org/patches/historical/dwm-r1578-pertag.diff diff --git a/dwm.suckless.org/patches/historical/push-5.3.c b/dwm.suckless.org/patches/historical/push-5.3.c @@ -1,56 +0,0 @@ -static Client * -prevtiled(Client *c) { - Client *p, *r; - - for (p = clients, r = NULL; p && p != c; p = p->next) - if (!p->isfloating && ISVISIBLE(p)) - r = p; - return r; -} - -static void -pushup(const Arg *arg) { - Client *c; - - if (!sel || sel->isfloating) - return; - if ((c = prevtiled(sel))) { - /* attach before c */ - detach(sel); - sel->next = c; - if (clients == c) - clients = sel; - else { - for (c = clients; c->next != sel->next; c = c->next); - c->next = sel; - } - } else { - /* move to the end */ - for (c = sel; c->next; c = c->next); - detach(sel); - sel->next = NULL; - c->next = sel; - } - focus(sel); - arrange(); -} - -static void -pushdown(const Arg *arg) { - Client *c; - - if (!sel || sel->isfloating) - return; - if ((c = nexttiled(sel->next))) { - /* attach after c */ - detach(sel); - sel->next = c->next; - c->next = sel; - } else { - /* move to the front */ - detach(sel); - attach(sel); - } - focus(sel); - arrange(); -} diff --git a/dwm.suckless.org/patches/historical/push-5.6.c b/dwm.suckless.org/patches/historical/push-5.6.c @@ -1,58 +0,0 @@ -static Client * -prevtiled(Client *c) { - Client *p, *r; - - for(p = selmon->clients, r = NULL; p && p != c; p = p->next) - if(!p->isfloating && ISVISIBLE(p)) - r = p; - return r; -} - -static void -pushup(const Arg *arg) { - Client *sel = selmon->sel; - Client *c; - - if(!sel || sel->isfloating) - return; - if((c = prevtiled(sel))) { - /* attach before c */ - detach(sel); - sel->next = c; - if(selmon->clients == c) - selmon->clients = sel; - else { - for(c = selmon->clients; c->next != sel->next; c = c->next); - c->next = sel; - } - } else { - /* move to the end */ - for(c = sel; c->next; c = c->next); - detach(sel); - sel->next = NULL; - c->next = sel; - } - focus(sel); - arrange(); -} - -static void -pushdown(const Arg *arg) { - Client *sel = selmon->sel; - Client *c; - - if(!sel || sel->isfloating) - return; - if((c = nexttiled(sel->next))) { - /* attach after c */ - detach(sel); - sel->next = c->next; - c->next = sel; - } else { - /* move to the front */ - detach(sel); - attach(sel); - } - focus(sel); - arrange(); -} diff --git a/dwm.suckless.org/patches/historical/xft.md b/dwm.suckless.org/patches/historical/xft.md @@ -0,0 +1,44 @@ +xft +=== + +Description +----------- + +The `xft` patch patch implements Xft. This allows users to utilize the UTF8 +character set. Look at the patch below which is more advance. + +The `xft-with-fallback-font` patch adds Xft and fallback-font support to dwm. +This patch was built on top of the [Xft patch written by +Quentin](http://lists.suckless.org/dev/1311/18279.html). With fallback font +support, multiple fonts can now be specified in config.h which are used to +render characters not present in the first font. If none of the user-specified +fonts contains a given character, this patch attempts to automatically fallback +to whatever suitable font it can find on the host system. +**NOTE: This is enabled by default when you are using the latest dwm-git.** + +With this patch, the "font" variable in config.h is superseded by the "fonts" +variable which is a priority-ordered list of fonts that should be used to +render text. Here's an example "fonts" definition: + + static const char *fonts[] = { + "Sans:size=10.5", + "VL Gothic:size=10.5", + "WenQuanYi Micro Hei:size=10.5", + }; + +At least one font must be specified, and a maximum of `DRW_FONT_CACHE_SIZE` +fonts can be used. + + +Download +-------- +* [dwm-6.0-xft.diff](historical/dwm-6.0-xft.diff) (6.6k) (16 May 2012) + * memory leak fixed and improved implementation. + * include config.def.h and config.mk changes. + +* [dwm-6.1-xft-with-fallback-font.diff](historical/dwm-git-20150228-xft-with-fallback-font.diff) (20k) + +Author +------ +* Lee Fallat (lf94)<ircsurfer33@gmail.com> +* [Eric Pruitt](https://github.com/ericpruitt/) diff --git a/dwm.suckless.org/patches/horizgrid.md b/dwm.suckless.org/patches/horizgrid.md @@ -0,0 +1,37 @@ +horizontal grid +=============== + +Description +----------- +This patch is a variant of [gapless_grid](gapless_grid). It arranges windows in a grid pattern in which every window is roughly the same size, adjusted such that there are no gaps. However, this layout arranges the windows in a horizontal grid, rather than a vertical grid. + +Horizontal Grid Layout +---------------------- + + horizgrid (###) + +--------+--------+ + | | | + | | | + +-----+--+--+-----+ + | | | | + | | | | + +-----+-----+-----+ + + gapless_grid + +--------+--------+ + | | | + | +--------+ + +--------+ | + | +--------+ + | | | + +--------+--------+ + +Download +-------- + + * [dwm-6.1-horizgrid.diff](dwm-6.1-horizgrid.diff) (20160108) + +Authors +------- + + * Marshall Mason - `<marshallmason2@gmail.com>` diff --git a/dwm.suckless.org/patches/index.md b/dwm.suckless.org/patches/index.md @@ -1,6 +1,18 @@ Patches ======= +There are two types of patches: The ones that fit to your personal taste and +the ones you think should be included in mainline dwm. + +For patches that should be included in mainline dwm see the +[community](//suckless.org/community) page and the hackers@ mailing list. + + +You can use the following instructions to generate and apply patches posted on +this wiki. On how to upload patches which fit your personal taste and you want +to show the community, see the [wiki](//suckless.org/wiki) page on how to edit +the pages you see here. + diff generation --------------- For git users: @@ -15,10 +27,9 @@ For tarballs: where `X.Y` is a dwm tag name or version number. - patch application ----------------- -For git users: +For git users, use `-3` to fix the conflict easily: cd dwm-directory git apply path/to/patch.diff diff --git a/dwm.suckless.org/patches/keycode.md b/dwm.suckless.org/patches/keycode.md @@ -1,12 +1,14 @@ Keycode ======== With this patch, handling key input is done with keycodes instead of keysyms. -This way, input is keyboard layout independant (adapt config.h to your keyboard using for exemple xev). +This way, input is keyboard layout independant (adapt config.h to your keyboard +using for exemple xev). Download -------- * [dwm-6.0-keycode.diff](dwm-6.0-keycode.diff) +* [dwm-20151110-5ed9c48-keycode.patch](dwm-20151110-5ed9c48-keycode.patch) Author ------ -* Quentin Rameau <quinq@quinq.eu.org> +* Quentin Rameau <quinq@fifth.space> diff --git a/dwm.suckless.org/patches/mark.md b/dwm.suckless.org/patches/mark.md @@ -0,0 +1,38 @@ + +Mark +==== + +Description +----------- + +This patch provides an mechanism to easily jump between any clients, or to swap any clients through shortcuts by introcuding mark. The mark is global, and only one mark is allowed at the same time. The marked client is distinguished from other clients by having a different border color. +This patch adds 3 functions and 2 variables: +* functions: + togglemark - mark/unmark current focused client. + swapclient - swap focused client with marked client, falls back to + zoom() if the mark is not being set. + swapfocus - swap focus with mark. +* variables: + normmarkcolor - border color for marked client. + selmarkcolor - border color for current focused client that is + also being marked. +And example of key mappings for this patch: + { MODKEY, XK_semicolon,togglemark, {0} }, + { MODKEY, XK_o, swapfocus, {0} }, + { MODKEY, XK_Return, swapclient, {0} }, +/*togglemark twice to remove the mark, emulates the behaviour of zoom()*/ + { MODKEY, XK_Return, togglemark, {0} }, + { MODKEY, XK_Return, togglemark, {0} }, + { MODKEY, XK_u, swapclient, {0} }, +/*swapclient and swapfocus at the same time, it's useful in some cases*/ + { MODKEY, XK_i, swapclient, {0} }, + { MODKEY, XK_i, swapfocus, {0} }, + +Download +-------- + +* [dwm-6.1-mark.diff](dwm-6.1-mark.diff) (7161b) (20160220) + +Author +------ +* phi <crispyforg@163.com> diff --git a/dwm.suckless.org/patches/movestack.md b/dwm.suckless.org/patches/movestack.md @@ -23,8 +23,8 @@ movestack(-1) will swap the client with the current focus with the previous clie ## Download - * [dwm-5.6.1-movestack.diff][1] (2.4k) (20090911) * [dwm-5.8.2-movestack.diff](movestack-5.8.2.diff) (2.6k) (20101102) + * [dwm-5.6.1-movestack.diff][1] (2.4k) (20090911) ## Author diff --git a/dwm.suckless.org/patches/noborder.md b/dwm.suckless.org/patches/noborder.md @@ -13,7 +13,7 @@ Download Patches against different versions of dwm are available at [dwm-clean-patches](https://github.com/jceb/dwm-clean-patches). - * [dwm-6.1-single_window_no_border.diff](dwm-6.1-single_window_no_border.diff) (3025b) (20140209) + * [dwm-6.1-single_window_no_border.diff](dwm-6.1-single_window_no_border.diff) (3047b) (20151111) * [dwm-10e232f9ace7-statusallmons.diff](dwm-10e232f9ace7-statusallmons.diff) (982b) (20120406) * [dwm-6.0-single_window_no_border.diff](dwm-6.0-single_window_no_border.diff) (2865b) (20120406) diff --git a/dwm.suckless.org/patches/pertag.md b/dwm.suckless.org/patches/pertag.md @@ -11,12 +11,10 @@ Download Patches against different versions of dwm are available at [dwm-clean-patches](https://github.com/jceb/dwm-clean-patches). - * [dwm-6.1-pertag.diff](dwm-6.1-pertag.diff) (6630b) (20140209) - * [dwm-10e232f9ace7-pertag.diff](dwm-10e232f9ace7-pertag.diff) (5955b) (20120406) - * [dwm-6.0-pertag_without_bar.diff](dwm-6.0-pertag_without_bar.diff) (5578b) (20140530) + * [dwm-6.1-pertag.diff](dwm-6.1-pertag.diff) (6.4K) (20151109) + * [dwm-git-20120406-pertag.diff](dwm-git-20120406-pertag.diff) (5955b) * [dwm-6.0-pertag.diff](dwm-6.0-pertag.diff) (5955b) (20120406) * [dwm-r1578-pertag.diff][9] (nmaster included in mainline) - * [dwm-5.8.2-pertag\_without\_bar.diff][8] * [dwm-5.8.2-pertag.diff][7] * [dwm-5.7.2-pertag.diff][6] * [dwm-pertag-5.6.1.diff][5] @@ -24,6 +22,11 @@ Patches against different versions of dwm are available at * [dwm-5.2-pertag.diff][3] * [dwm-5.1-pertag.diff][2] + * Using pertag but with the same barpos + * [dwm-6.1-pertag_without_bar.diff](dwm-6.1-pertag_without_bar.diff) (5.2K) (20151109) + * [dwm-6.0-pertag_without_bar.diff](dwm-6.0-pertag_without_bar.diff) (5578b) (20140530) + * [dwm-5.8.2-pertag\_without\_bar.diff][8] + Authors ------- * Jan Christoph Ebersbach - <jceb@e-jc.de> @@ -32,6 +35,7 @@ Authors * Updated by Sidney Amani - `<seed at uffs dot org>` * Updated by William Light - `<wrl at illest dot net>` * Updated by termac - `<terror.macbeth.I at gmail dot com>` + * Updated by Ivan Tham - `pickfire at riseup dot net` [1]: historical/taglayouts [2]: http://v4hn.de/patches/dwm-5.1-pertag.diff @@ -39,6 +43,6 @@ Authors [4]: historical/dwm-5.4-pertag.diff [5]: historical/dwm-pertag-5.6.1.diff [6]: historical/dwm-5.7.2-pertag.diff -[7]: dwm-5.8.2-pertag.diff -[8]: dwm-5.8.2-pertag_without_bar.diff -[9]: dwm-r1578-pertag.diff +[7]: historical/dwm-5.8.2-pertag.diff +[8]: historical/dwm-5.8.2-pertag_without_bar.diff +[9]: historical/dwm-r1578-pertag.diff diff --git a/dwm.suckless.org/patches/push.c b/dwm.suckless.org/patches/push.c @@ -1,58 +0,0 @@ -static Client * -prevtiled(Client *c) { - Client *p, *r; - - for(p = selmon->clients, r = NULL; p && p != c; p = p->next) - if(!p->isfloating && ISVISIBLE(p)) - r = p; - return r; -} - -static void -pushup(const Arg *arg) { - Client *sel = selmon->sel; - Client *c; - - if(!sel || sel->isfloating) - return; - if((c = prevtiled(sel))) { - /* attach before c */ - detach(sel); - sel->next = c; - if(selmon->clients == c) - selmon->clients = sel; - else { - for(c = selmon->clients; c->next != sel->next; c = c->next); - c->next = sel; - } - } else { - /* move to the end */ - for(c = sel; c->next; c = c->next); - detach(sel); - sel->next = NULL; - c->next = sel; - } - focus(sel); - arrange(selmon); -} - -static void -pushdown(const Arg *arg) { - Client *sel = selmon->sel; - Client *c; - - if(!sel || sel->isfloating) - return; - if((c = nexttiled(sel->next))) { - /* attach after c */ - detach(sel); - sel->next = c->next; - c->next = sel; - } else { - /* move to the front */ - detach(sel); - attach(sel); - } - focus(sel); - arrange(selmon); -} diff --git a/dwm.suckless.org/patches/push.md b/dwm.suckless.org/patches/push.md @@ -8,8 +8,8 @@ static Key keys[] = { ... - { MODKEY|ControlMask, XK_j, pushdown, {0} }, - { MODKEY|ControlMask, XK_k, pushup, {0} }, + { MODKEY|ControlMask, XK_j, pushdown, {0} }, + { MODKEY|ControlMask, XK_k, pushup, {0} }, `push_no_master` is the same as the regular `push` patch, but it does not push up nor push down into the master area. We have zoom() for that. @@ -17,13 +17,10 @@ Patches against different versions of dwm are available at [dwm-clean-patches](https://github.com/jceb/dwm-clean-patches). - * [dwm-6.1-push.diff](dwm-6.1-push.diff) (1402b) (20140209) - * [dwm-10e232f9ace7-push.diff](dwm-10e232f9ace7-push.diff) (1332b) (20120406) - * [dwm-6.0-push.diff](dwm-6.0-push.diff) (1332b) (20120406) + * [dwm-6.0-push.diff](dwm-6.0-push.diff) (1332b) - 2012/4/6 * [dwm-6.0-push_no_master.diff](dwm-6.0-push_no_master.diff) - * [push.c](push.c) (dwm 5.7.1) (20090927) - * [push-5.6.c](historical/push-5.6.c) (1K) (20090709) - * [push-5.3.c](historical/push-5.3.c) (1K) (20090124) + * [dwm-6.1-push.diff](dwm-6.1-push.diff) (1402b) - 2014/2/9 + * [dwm-6.1-push_no_master.diff](dwm-6.1-push_no_master.diff) - 2015/11/21 ## Note This patch seems to be equivalent to the [movestack](movestack) patch. diff --git a/dwm.suckless.org/patches/resizecorners.md b/dwm.suckless.org/patches/resizecorners.md @@ -6,8 +6,10 @@ By default, windows only from the bottom right corner. With this Patch, the mous ## Download + * [dwm-6.1-resizecorners.diff](dwm-6.1-resizecorners.diff) (17.02.2016) * [dwm-6.0-resizecorners.diff](dwm-6.0-resizecorners.diff) (12.05.2015) ## Author * dusty - <dusty@teknik.io> + * Klemens Nanni <[kl3@posteo.org](mailto:kl3@posteo.org)> (6.1 version) diff --git a/dwm.suckless.org/patches/statuscolors.md b/dwm.suckless.org/patches/statuscolors.md @@ -19,7 +19,7 @@ Add code to your status script to output the raw characters '\x03' to switch to The following definition in 'config.h': #define NUMCOLORS 4 - static const char colors[NUMCOLORS][ColLast][8] = { + static const char colors[NUMCOLORS][MAXCOLORS][8] = { // border foreground background { "#000033", "#dddddd", "#000033" }, // normal { "#000088", "#ffffff", "#000088" }, // selected diff --git a/dwm.suckless.org/patches/swallow.md b/dwm.suckless.org/patches/swallow.md @@ -0,0 +1,34 @@ +# terminals swallow windows + +## Description + +This patch adds "window swallowing" to dwm, a la `rio` from Plan 9. + +Windows that are marked with the `isterminal` flag (settable using rules in `config.h`) will swallow a window opened by any descendant processes. +For example, if you open a terminal and then in that terminal type `xclock`, the `xclock` window takes the place of that terminal window. +Closing the `xclock` window restores the terminal window in the current position. + +This patch is useful for users who tend to do most or all of their work from the command line, but sometimes need to use a graphical program. +This patch avoids cluttering the desktop with unused terminals. + +(`dmenu` could be used, but if you are deep in a directory hierarchy and want to, say, view a PDF, cutting and pasting the path to `dmenu` takes longer than just running `mupdf`.) + +## Download +Please see [deadpixi-dwm](https://github.com/deadpixi/deadpixi-dwm) for the development site. + +Patches are also available here: + + * [dwm-6.1-swallowing.diff](dwm-6.1-swallowing.diff) (9319b) - 2016/1/27 + +## Note +The window swallowing functionality requires `dwm` to walk the process tree, which is an inherently OS-specific task. +Only Linux is supported at this time. +Please contact the author (jking@deadpixi.com) if you would like to help expand the list of supported operating systems. + +Also please note that building with this patch requires `libxcb`, `Xlib-libxcb`, and `xcb-res`. +This is due to the use of the latest revision of the X Resource Extension, which is unsupported in vanilla Xlib. + +Only terminals created by local processes can swallow windows, and only windows created by local processes can be swallowed. + +## Author + * Rob King <jking@deadpixi.com> diff --git a/dwm.suckless.org/patches/systray.md b/dwm.suckless.org/patches/systray.md @@ -11,12 +11,13 @@ Download Patches against different versions of dwm are available at [dwm-clean-patches](https://github.com/jceb/dwm-clean-patches). - * [dwm-14343e69cc59-systray.diff](dwm-14343e69cc59-systray.diff) () (20150808) - * [dwm-6.1-systray.diff](dwm-6.1-systray.diff) (21630b) (20140209) - * [dwm-c794a9f5ae5e-systray.diff](dwm-c794a9f5ae5e-systray.diff) (19946b) (20130119) + * [dwm-git-20160103-systray.diff](dwm-git-20160103-systray.diff) (3465bed) + * [dwm-6.1-systray.diff](dwm-6.1-systray.diff) (22K) (20151109) + * [dwm-git-20130119-systray.diff](dwm-git-20130119-systray.diff]) (19946b) * [dwm-6.0-systray.diff](dwm-6.0-systray.diff) (19788b) (20130119) Author ------ * Jan Christoph Ebersbach <jceb@e-jc.de> * Eon S. Jeon <esjeon@hyunmu.am> (14343e69cc59) + * David Phillips (5ed9c48 (6.1), and 20160103) diff --git a/dwm.suckless.org/patches/tab.md b/dwm.suckless.org/patches/tab.md @@ -134,6 +134,7 @@ Download Old versions + * [dwm-master\_2015-10-20\_7e1182c-tab-v2b.diff](historical/dwm-master\_2015-10-20\_7e1182c-tab-v2b.diff), [dwm-master\_2015-10-20\_7e1182c-pertag-tab-v2b.diff](historical/dwm-master\_2015-10-20\_7e1182c-pertag-tab-v2b.diff) * [dwm-master\_2015-03-05\_14343e-tab-v2b.diff](historical/dwm-master\_2015-03-05\_14343e-tab-v2b.diff), [dwm-master\_2015-03-05\_14343e-pertag-tab-v2b.diff](historical/dwm-master\_2015-03-05\_14343e-pertag-tab-v2b.diff) * [dwm-6.0-tab-v2b.diff](historical/dwm-6.0-tab-v2b.diff), [dwm-6.0-pertag-tab-v2b.diff](historical/dwm-6.0-pertag-tab-v2b.diff) * [dwm-master\_2013-08-27\_cdec978-tab-v2a.diff](historical/dwm-master_2013-08-27_cdec978-tab-v2a.diff), [dwm-master\_2013-08-27\_cdec978-pertag-tab-v2a.diff](historical/dwm-master_2013-08-27_cdec978-pertag-tab-v2a.diff) diff --git a/dwm.suckless.org/patches/urgentborder.md b/dwm.suckless.org/patches/urgentborder.md @@ -8,8 +8,8 @@ Use config.h item "urgbordercolor" to change it. ## Download - * [dwm-6.1-make-the-borders-of-urgent-windows-a-different-color.diff](dwm-6.1-make-the-borders-of-urgent-windows-a-different-color.diff) (2.2K) (20150307) - + * [dwm-6.1-urg-border.diff](dwm-6.1-urg-border.diff) (2.2K) (20150307) + ## Author * Alexander Huemer - alexander dot huemer dot xx dot vu (Based on former work by Ray Kohler - ataraxia937 gmail com) diff --git a/dwm.suckless.org/patches/warp.md b/dwm.suckless.org/patches/warp.md @@ -4,19 +4,20 @@ warp Description ----------- -This patch warps the mouse cursor each time another window gets focused to the -middle of the window. +This patch warps the mouse cursor to the center of the currently focused window +or screen when the mouse cursor is (a) on a different screen or (b) on top of a +different window. Download -------- -* [dwm-5.9-warp.diff](dwm-5.9-warp.diff) (1.3k) (20111028) -* [dwm-r1525-warp.diff](historical/dwm-r1525-warp.diff) (2.3k) (20100911) - In the patch for r1525, there is a problem with this caused by `XSelectInput`, causing the - statusbar to freeze. Interestingly, the [stdin](stdin) patch works around this. +* [dwm-5.9-warp.diff](dwm-5.9-warp.diff) (20111028) +* [dwm-6.1-warp.diff](dwm-6.1-warp.diff) (20151215) Author ------ * Evan Gates (emg) <evan.gates@gmail.com> * Enno Boland (Gottox) +* Jochen Sprickerhof +* Winston Weinert (winny) <winston@ml1.net> diff --git a/dwm.suckless.org/patches/xft-with-fallback-fonts.md b/dwm.suckless.org/patches/xft-with-fallback-fonts.md @@ -1,36 +0,0 @@ -Xft With Fallback-Font Support -============================== - -Description ------------ - -Adds Xft and fallback-font support to dwm. This patch was built on top of the -[Xft patch written by Quentin](http://lists.suckless.org/dev/1311/18279.html). -With fallback font support, multiple fonts can now be specified in config.h -which are used to render characters not present in the first font. If none of -the user-specified fonts contains a given character, this patch attempts to -automatically fallback to whatever suitable font it can find on the host -system. - -With this patch, the "font" variable in config.h is superseded by the "fonts" -variable which is a priority-ordered list of fonts that should be used to -render text. Here's an example "fonts" definition: - - static const char *fonts[] = { - "Sans:size=10.5", - "VL Gothic:size=10.5", - "WenQuanYi Micro Hei:size=10.5", - }; - -At least one font must be specified, and a maximum of `DRW_FONT_CACHE_SIZE` -fonts can be used. - -Download --------- - -* [dwm-6.1-xft-with-fallback-font.diff](dwm-6.1-xft-with-fallback-font.diff) (20k) (2015-02-28) - -Author ------- - -* [Eric Pruitt](https://github.com/ericpruitt/) diff --git a/dwm.suckless.org/patches/xft.md b/dwm.suckless.org/patches/xft.md @@ -1,19 +0,0 @@ -xft -=== - -Description ------------ - -This patch implements Xft. This allows users to utilize the UTF8 character set. - -Download --------- - -* [dwm-6.0-xft.diff](dwm-6.0-xft.diff) (6.6k) (16 May 2012) - * memory leak fixed and improved implementation. - - -Author ------- - -* Lee Fallat (lf94)<ircsurfer33@gmail.com> diff --git a/dwm.suckless.org/scripts/simple_monitors.md b/dwm.suckless.org/scripts/simple_monitors.md @@ -12,10 +12,16 @@ Battery Your battery may be called something different, so check /proc/acpi for its name. Also, change 89000 to whatever the capacity is for your battery. This returns the remaining battery power as a percentage. - $(echo $(awk '/rem/ { print $3/89000 }' /proc/acpi/battery/BAT0/state| hoc| cut -c3,4)% + $(echo $(awk '/rem/ { print $3/89000 }' /proc/acpi/battery/BAT0/state| hoc| cut -c3,4)% hoc comes from plan9port or 9base. +Depending on your system, you can also use + + cat /sys/class/power_supply/BAT0/capacity + +to get your battery status in percentage. + Ram used --- @@ -33,7 +39,7 @@ Returns the temperature of the cpu, in celcius. Volume --- - amixer get Front | tail -1 | sed 's/.*\[\([0-9]*%\)\].*/\1/' + amixer get Front | tail -n1 | awk '{ print $5 }' | tr -d [] Change "Front" to your audio device diff --git a/dwm.suckless.org/tutorial.md b/dwm.suckless.org/tutorial.md @@ -1,3 +1,8 @@ +Launching +--------- + +To launch dwm, ideally you should setup a `~/.xinitrc` with at least `exec dwm`. + Introduction ------------ @@ -14,21 +19,40 @@ By default there are 9 tags. Window model ------------ -Launch a few terminals `[Shift]+[Alt]+[Enter]` and dwm will _tile_ the windows +Launch a few terminals with `[Shift]+[Alt]+[Enter]` and dwm will _tile_ the windows between the **master** and **stack**. A new terminal appears on the **master** window. Existing windows are pushed upon a **stack** to the right of the screen. `[Alt]+[Enter]` toggles windows between master and stack. -To move a terminal pane/tile/window to another tag you select the window by -hovering over the window. Then execute the bind `[Shift]+[Alt]+[2]` to move the -window to the 2 tag. `[Alt]+[2]` moves your focus to tag 2. + +------+----------------------------------+--------+ + | tags | title | status + + +------+---------------------+------------+--------+ + | | | + | | | + | | | + | | | + | master | stack | + | | | + | | | + | | | + | | | + +----------------------------+---------------------+ + +Moving Around +------------- + +To **move to another terminal**, press `[Alt]+[j]` or `[Alt]+[k]`. + +To **move a terminal to another _tag_**, hover to the terminal and press `[Shift]+[Alt]+[2]`. + +To **focus on another _tag_**, press `[Alt]+[tag number]`. + +To **move a terminal to master or stack**, press `[Alt]+[d]` or `[Alt]+[i]`. As stated in the dwm manpage, you can click tags with the left mouse button and simulating `[Alt]+[tag number]`, but you can also click another tag with the right mouse button in order to bring those windows additionally into your current focus. -To kill a window: - - [Shift]+[Alt]+[c] +To **kill a window**, press `[Shift]+[Alt]+[c]`. Layouts ------- @@ -82,14 +106,7 @@ Using the tools of X.org, this can be set using: % xsetroot -name "Some Text" There are various tools and methods to populate this text with useful -information from your system or services running on your system. A barebone -for doing this in C is [dwmstatus](http://dwm.suckless.org/dwmstatus/). -See the [xinitrc](http://dwm.suckless.org/xinitrc.example) -example for how to do it using a script. - -Launching ---------- - -To launch dwm, ideally you should setup an -[xinitrc](http://dwm.suckless.org/xinitrc.example). - +information from your system or services running on your system. A barebone for +doing this in C is [dwmstatus](http://dwm.suckless.org/dwmstatus/). See the +[xinitrc](http://dwm.suckless.org/xinitrc.example) example for how to do it +using a script. diff --git a/st.suckless.org/index.md b/st.suckless.org/index.md @@ -31,7 +31,7 @@ be implemented or fixed. What has been implemented: -* 256 colors +* 256 colors and [true colors](https://gist.github.com/XVilka/8346728) * most VT10X escape sequences * utf8 * X11 copy/paste diff --git a/st.suckless.org/patches/1clipboard.diff b/st.suckless.org/patches/1clipboard.diff @@ -1,14 +0,0 @@ -diff --git a/st.c b/st.c -index bb64c55..5ff1a36 100644 ---- a/st.c -+++ b/st.c -@@ -1155,6 +1155,9 @@ xsetsel(char *str, Time t) { - XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); - if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) - selclear(0); -+ -+ clipcopy(NULL); -+ - } - - void diff --git a/st.suckless.org/patches/1clipboard.md b/st.suckless.org/patches/1clipboard.md @@ -1,25 +0,0 @@ -# One clipboard - -## Description - -<abbr title="simple terminal">st</abbr> since [March 2015 only sets PRIMARY on -selection](http://git.suckless.org/st/commit/?id=28259f5750f0dc7f52bbaf8b746ec3dc576a58ee), -in accordance to the [Freedesktop -standard](http://standards.freedesktop.org/clipboards-spec/clipboards-latest.txt). - -However I don't like this <abbr title="User eXperience">UX</abbr>. I don't like -having to think about two clipboards. I don't like having to use typically -three key combination to copy my selected text into the clipboard used by my -browser. - -## Download - -* [1clipboard.diff](1clipboard.diff) - -or - -Append `clipcopy(NULL);` to the end of the xsetsel function in [st.c](http://git.suckless.org/st/tree/st.c). - -## Author - -[Kai Hendry](http://hendry.iki.fi/) diff --git a/st.suckless.org/patches/argbbg.md b/st.suckless.org/patches/argbbg.md @@ -5,21 +5,22 @@ argbbg ## Description ## This patch allows users to change the opacity of the background. -Note that **you need an X composite manager** to make this patch effective. (e.g. compton, xcompmgr) +Note that *you need an X composite manager* (e.g. compton, xcompmgr) to +make this patch effective. ## Important Notes ## - The alpha value affects the default background only. - - The color designated by `defaultbg` should not be used elsewhere. + - The color designated by 'defaultbg' should not be used elsewhere. - Embedding might fail after applying this patch. ## Download ## * [st-0.4.1-argbbg.diff](st-0.4.1-argbbg.diff) * [st-0.5-argbbg.diff](st-0.5-argbbg.diff) - * [st-git-20141122-argbbg.diff](st-git-20141122-argbbg.diff) - * [st-git-20150611-argbbg.diff](st-git-20150611-argbbg.diff) + * [st-0.6-argbbg.diff](st-0.6-argbbg.diff) + * [st-git-20160131-argbbg.diff](st-git-20160131-argbbg.diff) ## Authors ## * Eon S. Jeon - esjeon@hyunmu.am * pr - protodev@gmx.net (st-0.5 port) - * Juan Aguilar - aritmeeul@gmail.com (st-git-20141122 port) - * Laslo Hunhold - dev@frign.de (st-git-20150601 port) + * Laslo Hunhold - dev@frign.de (st-0.6 port) + * David Phillips - dbphillipsnz@gmail.com (st-git-20160131 port) diff --git a/st.suckless.org/patches/boldcolor.md b/st.suckless.org/patches/boldcolor.md @@ -4,16 +4,16 @@ boldcolor Description ----------- -This is a hack to allow using different color for bold, italic -or underlined text when the text is in defaultfg color otherwise. +This is a hack allowing to use different colors for bold, italic +and underlined text when the text would be in defaultfg color otherwise. -Makes the special attributes more visible, when no bold or italic -font is available, or the defaultfg is a special color (>255 value). +This makes the special attributes more visible when no bold or italic +font is available or defaultfg is a special color (> 255). Usage ----- -example config.h +config.h example: static const char *colorname[] = { // ... @@ -39,11 +39,9 @@ example config.h Download -------- -* [st-0.3-boldcolor.diff][0] - -[0]: st-0.3-boldcolor.diff +* [st-0.3-boldcolor.diff](st-0.3-boldcolor.diff) Author ------ - * Szabolcs Nagy - nsz + * Szabolcs Nagy - nsz@port70.net diff --git a/st.suckless.org/patches/clipboard.md b/st.suckless.org/patches/clipboard.md @@ -0,0 +1,21 @@ +# clipboard + +## Description + +st only sets PRIMARY on selection since +[March 2015](http://git.suckless.org/st/commit/?id=28259f5750f0dc7f52bbaf8b746ec3dc576a58ee) +according to the +[Freedesktop standard](http://standards.freedesktop.org/clipboards-spec/clipboards-latest.txt). + +This patch brings back the old behaviour, namely additionally setting +CLIPBOARD. + +## Download + +* [st-0.6-clipboard.diff](st-0.6-clipboard.diff) +* [st-git-20150917-clipboard.diff](st-git-20150917-clipboard.diff) + +## Authors + + * Kai Hendry - hendry@iki.fi + * Laslo Hunhold - dev@frign.de (st-git-20150917 port) diff --git a/st.suckless.org/patches/configwordbreak.md b/st.suckless.org/patches/configwordbreak.md @@ -1,29 +0,0 @@ -configwordbreak -=============== - -Description ------------ - -This is a patch to allow configuring which characters are used as -word boundaries for double click selection (instead of just ' '). -This feature is already implemented in all versions later than 0.5. - -Usage ------ - -example config.h - - #define WORD_BREAK " ()<>[]\"" - -Download --------- -* [st-0.3-configwordbreak.diff](st-0.3-configwordbreak.diff) -* [st-0.4-configwordbreak.diff](st-0.4-configwordbreak.diff) -* [st-0.4.1-configwordbreak.diff](st-0.4.1-configwordbreak.diff) -* [st-0.5-configwordbreak.diff](st-0.5-configwordbreak.diff) - -Author ------- - - * Stephen Paul Weber - singpolyma - * FRIGN - dev@frign.de (st-0.4, st-0.4.1, st-0.5 ports) diff --git a/st.suckless.org/patches/copyurl.md b/st.suckless.org/patches/copyurl.md @@ -4,17 +4,24 @@ copyurl Description ----------- -Select and copy the last URL in the display. Multiple invocations cycle through -the available URLs. +Select and copy the last URL displayed with Mod1+l. +Multiple invocations cycle through the available URLs. + +Notes +----- + +URLs spanning multiple lines are not handled and only the first +URL on each line is selected. Download -------- -* [st-git-20141017-copyurl.diff](st-git-20141017-copyurl.diff) -* [st-git-20150601-copyurl.diff](st-git-20150601-copyurl.diff) + * [st-0.6-copyurl.diff](st-0.6-copyurl.diff) + * [st-git-20160210-copyurl.diff](st-git-20160210-copyurl.diff) -Author ------- +Authors +------- * Brandon Mulcahy - brandon@jangler.info - * FRIGN - dev@frign.de (git port) + * Laslo Hunhold - dev@frign.de (st-0.6 port) + * David Phillips - dbphillipsnz@gmail.com (st-git-20160210 port) diff --git a/st.suckless.org/patches/delkey.md b/st.suckless.org/patches/delkey.md @@ -4,14 +4,16 @@ delkey Description ----------- -Return BS in Backspace and DEL in Delete key. +Return BS on pressing backspace and DEL on pressing the delete key. Download -------- -* [st-git-delkey.diff](st-git-delkey.diff) + * [st-0.6-delkey.diff](st-0.6-delkey.diff) + * [st-git-20150917-delkey.diff](st-git-20150917-delkey.diff) -Author ------- +Authors +------- * Roberto E. Vargas Caballero - k0ga@shike2.com + * Laslo Hunhold - dev@frign.de (st-0.6, st-git-20150917 ports) diff --git a/st.suckless.org/patches/externalpipe.md b/st.suckless.org/patches/externalpipe.md @@ -1,44 +1,36 @@ -External Pipe -============= +externalpipe +============ Description ----------- -This patch lets you write st's screen text out through a pipe, for example, -url-select (below). +Reading and writing st's screen through a pipe. Example ------- -Bind alt+u to extract all visible urls and present dmenu, to choose and open -said urls: +config.h example, binding Mod1+u to extract all visible URLs and present +dmenu to select and open one: static Shortcut shortcuts[] = { ... - { MODKEY, 'u', externalpipe, { .s = "xurls | dmenu -l 10 | xargs -r open" } }, + { MODKEY, 'u', externalpipe, { .v = "xurls | dmenu -l 10 | xargs -r open" } }, }; - -([xurls][1] and [open][2] are external scripts) +([xurls](https://raw.github.com/bobrippling/perlbin/master/xurls) and +[open](https://github.com/bobrippling/open) are external scripts) Download -------- -* [st-0.4.1-externalpipe.diff][0] -* [st-0.5-externalpipe.diff][3] -* [st-0.6-externalpipe.diff][4] -* [st-git-20150824-externalpipe.diff][5] - -[0]: st-0.4.1-externalpipe.diff -[1]: https://raw.github.com/bobrippling/perlbin/master/xurls -[2]: https://github.com/bobrippling/open -[3]: http://witsquash.com/~marty/st-0.5-externalpipe.diff -[4]: st-0.6-externalpipe.diff -[5]: st-git-20150824-externalpipe.diff +* [st-0.4.1-externalpipe.diff](st-0.4.1-externalpipe.diff) +* [st-0.5-externalpipe.diff](st-0.5-externalpipe.diff) +* [st-0.6-externalpipe.diff](st-0.6-externalpipe.diff) +* [st-git-20160204-externalpipe.diff](st-git-20160204-externalpipe.diff) +Authors +------- -Author ------- - - * Rob Pilling - my name @ gmail + * Rob Pilling - robpilling@gmail.com + * Laslo Hunhold - dev@frign.de (st-0.4.1, st-0.5, st-0.6, st-git-20150917 ports) diff --git a/st.suckless.org/patches/hide_X_cursor.md b/st.suckless.org/patches/hide_X_cursor.md @@ -1,20 +0,0 @@ -Hide X cursor -============= - -Description ------------ - -Hide the X cursor whenever a key is pressed and show it back when the mouse is -moved in the terminal window. - -Download --------- - -* [st-0.5-hidexcursor.diff](st-0.5-hidexcursor.diff) -* [st-0.6-hidexcursor.diff](st-0.6-hidexcursor.diff) -* [st-git-hidexcursor.diff](st-git-hidexcursor.diff) - -Author ------- - - * Ivan Delalande - colona diff --git a/st.suckless.org/patches/hidecursor.md b/st.suckless.org/patches/hidecursor.md @@ -0,0 +1,21 @@ +hidecursor +========== + +Description +----------- + +Hide the X cursor whenever a key is pressed and show it back when the mouse +is moved in the terminal window. + +Download +-------- + +* [st-0.5-hidecursor.diff](st-0.5-hidecursor.diff) +* [st-0.6-hidecursor.diff](st-0.6-hidecursor.diff) +* [st-git-20150917-hidecursor.diff](st-git-20150917-hidecursor.diff) + +Author +------ + + * Ivan Delalande - colona@ycc.fr + * Laslo Hunhold - dev@frign.de (st-git-20150917 port) diff --git a/st.suckless.org/patches/openbsd.md b/st.suckless.org/patches/openbsd.md @@ -0,0 +1,37 @@ +openbsd +======= + +Description +----------- + +OpenBSD primarily searches for terminfo descriptions in +terminfo databases before considering terminfo files. +Given the terminfo currently stored in the global database +is for st 0.1.1, this leads to conflicts and misbehaviour. + +This patch renames st to st-git forcing OpenBSD to use the provided +terminfo file. + + +Notes +----- + +Once a new stable version of st is out, the corresponding changes +to st.info can be pushed upstream to ncurses and then be merged +back to OpenBSD, effectively making this patch obsolete for +future stable releases. +More information on this issue can be found in this +[thread](http://marc.info/?l=openbsd-misc&m=139540215025526&w=2). + + +Download +-------- + +* [st-git-20150920-openbsd.diff](st-git-20150920-openbsd.diff) + + +Authors +------- + + * Nils Reuße - nilsreusse@gmail.com + * Laslo Hunhold - dev@frign.de (st-git-20150920 port) diff --git a/st.suckless.org/patches/scrollback.md b/st.suckless.org/patches/scrollback.md @@ -1,19 +1,35 @@ -# Scrollback +scrollback +========== -## Description +Description +----------- -Scroll back through terminal output. +Scroll back through terminal output using Shift+{PageUp, PageDown}. -## Download +Download +-------- -Apply only one of them: +* [st-git-20151217-scrollback.diff](st-git-20151217-scrollback.diff) -* [st-scrollback.diff](st-scrollback.diff) (against current git master) -* [st-scrollback-shift-mouse.diff](st-scrollback-shift-mouse.diff) - With shift - mouse +Apply the following patch on top of the previous to allow scrolling +using `Shift+MouseWheel`. -## Author +* [st-git-20151106-scrollback-mouse.diff](st-git-20151106-scrollback-mouse.diff) - * Jochen Sprickerhof - dwm @ jochen . sprickerhof . de - * M Farkas-Dyck - strake888 @ gmail . com - * Ivan Tham - pickfire @ riseup . net (The gluer) +Apply the following patch on top of the previous two to allow scrollback using +mouse wheel only when not in `MODE_ALTSCREEN`. eg. The content is being +scrolled instead of the scrollback buffer in `less`. Consequently the Shift +modifier for scrolling is not needed anymore. **Note: It might break other +mkeys excluding scrolling functions.** + +* [st-git-20160203-scrollback-mouse-altscreen.diff](st-git-20160203-scrollback-mouse-altscreen.diff) + +Authors +------- + + * Jochen Sprickerhof - dwm@jochen.sprickerhof.de + * M Farkas-Dyck - strake888@gmail.com + * Ivan Tham - pickfire@riseup.net (mouse scrolling, st-git-20151122 port) + * Laslo Hunhold - dev@frign.de (unscrambling, st-git-20151106 port) + * Ori Bernstein - ori@eigenstate.org (fix memory bug, st-git-20151216 port) + * Matthias Schoth - mschoth@gmail.com (auto altscreen scrolling) diff --git a/st.suckless.org/patches/solarized.md b/st.suckless.org/patches/solarized.md @@ -0,0 +1,58 @@ +solarized +========= + +Description +----------- + +[Solarized](http://ethanschoonover.com/solarized) is a color scheme by +Ethan Schoonover which exists in a dark and a light variant. These +patches make the Solarized color scheme available for st. + + +Notes +----- + +Once applied, only the terminal colors are changed. For applications +such as tmux or vim, you may need to +[adjust the colors there as well](https://bbs.archlinux.org/viewtopic.php?id=164108). + + +Example +------- + +->[![Screenshot](st-solarized-light-s.png)](st-solarized-light.png)<- + +->[![Screenshot](st-solarized-dark-s.png)](st-solarized-dark.png)<- + +The font used is Source Code Pro. + +Download +-------- + +To get correct colors, you first need to apply the following patch +to disable lighting up bold colors. + + * [st-0.5-no-bold-colors.diff](st-0.5-no-bold-colors.diff) + * [st-0.6-no-bold-colors.diff](st-0.6-no-bold-colors.diff) + * [st-git-20150917-no-bold-colors.diff](st-git-20150917-no-bold-colors.diff) + +Choose one of the following patches to get either the light +or the dark color scheme: + +*Light*: + + * [st-0.5-solarized-light.diff](st-0.5-solarized-light.diff) + * [st-0.6-solarized-light.diff](st-0.6-solarized-light.diff) + * [st-git-20151119-solarized-light.diff](st-git-20151119-solarized-light.diff) + +*Dark*: + + * [st-0.5-solarized-dark.diff](st-0.5-solarized-dark.diff) + * [st-0.6-solarized-dark.diff](st-0.6-solarized-dark.diff) + * [st-git-20151119-solarized-dark.diff](st-git-20151119-solarized-dark.diff) + +Authors +------- + + * Nils Reuße - nilsreusse@gmail.com + * Laslo Hunhold - dev@frign.de (st-0.5, st-0.6, st-git-20150917 ports) diff --git a/st.suckless.org/patches/solarized_color_scheme.md b/st.suckless.org/patches/solarized_color_scheme.md @@ -1,58 +0,0 @@ -Solarized color scheme -====================== - -Description ------------ - -[Solarized][1] is a color scheme by Ethan Schoonover which exists in a -dark and a light variant. These patches make the solarized colors -available on st. - - -Notes ------ - -No matter if you choose the light or dark theme, to get the correct -colors, you *always* have to apply the [patch to st.c][8] (if you're -using the latest git version of st, use [this patch to st.c][3]). Then, -apply one of the patches for either the [light][4] or the [dark][5] -version of solarized. - -These patches apply to the latest git of st, but should apply to older -versions as well. - -Once applied, only the terminal colors are changed. For applications -such as tmux or vim, you may need to adjust the colors there as well. -You find more information in my [thread][2] at the arch linux forums. - - -Example -------- - -[![Screenshot](st-solarized-light-s.png)](st-solarized-light.png) -[![Screenshot](st-solarized-dark-s.png)](st-solarized-dark.png) - -The font is [Source Code Pro][6]. - -Download --------- - - * [st-0.5-no-bold-colors.diff][7] - * [st-0.6-no-bold-colors.diff][8] - * [st-no-bold-colors.diff][3] - * [st-solarized-light.diff][4] - * [st-solarized-dark.diff][5] - -[1]: http://ethanschoonover.com/solarized -[2]: https://bbs.archlinux.org/viewtopic.php?id=164108 -[3]: st-no-bold-colors.diff -[4]: st-solarized-light.diff -[5]: st-solarized-dark.diff -[6]: http://en.wikipedia.org/wiki/Source_Code_Pro -[7]: st-0.5-no-bold-colors.diff -[8]: st-0.6-no-bold-colors.diff - -Author ------- - - * Nils Reu&szlig;e - nilsreusse @ gmail diff --git a/st.suckless.org/patches/spoiler.md</