Dwm on CentOS
This article is not about dmw only but about setting up a simple Linux Workstation based on CentOS 7.
Inhaltsverzeichnis
Packages
First things first. You need the following to get packages installed.
yum install -y ncurses-term epel-release xterm ftp libX11-devel libXinerama-devel
If you want to get gnome-terminal version 3.6.2 running you will have to install the following packages.
yum install -y glib2-devel gtk2-devel gtk3-devel GConf2-devel vte3-devel gsettings-desktop-schemas-devel libSM-devel itstool
If you want to use feh (image viewer) you need the followig packages to get it compiled.
yum install -y imlib2-devel libcurl-devel libXt libXt-devel libXft libXft-devel
Personalization
Bash and VI
~/.bashrc
# .bashrc PS1='\h\w\$ ' export EDITOR=vi export TERM=dtterm PATH=/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin # User specific aliases and functions alias vi='/usr/bin/vim -X' alias l='/bin/ls --group-directories-first -lah | more'
~/.vim
syntax on filetype indent plugin off filetype indent off "set number "show line numbers set nowrap "dont wrap lines "set linebreak "wrap lines at convenient points set t_Co=256 "tell the term has 256 colors "vertical/horizontal scroll off settings set scrolloff=3 set sidescrolloff=7 set sidescroll=1 "mouse support "set mouse=a "set ttymouse=xterm2 "default indent settings set tabstop=4 set shiftwidth=4 set softtabstop=4 set expandtab "set autoindent set backspace=2 set incsearch "find the next match as we type the search set nohlsearch "no hilight of search string set ruler
XDMCP
It seems that XDMCP is working on CentOS 6/6.5 but does not work on CentOS 7 anymore. However, a configuration similar to the following should do the trick.
/etc/gdm/custom.conf
# GDM configuration storage [daemon] User=gdm Group=gdm [security] DisallowTCP=false AllowRemoteRoot=true [xdmcp] Enable=true DisplayPerHost=10 HonorIndirect=false MaxPending=4 MaxSessions=32 MaxWait=30 MaxWaitIndirect=30 Port=177 [greeter] IncludeAll=true [chooser] Multicast=false [debug] Enable=false
dwm Configuration
config.h
Keep in mind to get patches installed first.
/* See LICENSE file for copyright and license details. */ /* appearance */ // static const char font[] = "-*-courier-*-*-*--14-*-*-*-*-*-*-*"; static const char font[] = "-*-xbmicons-medium-r-*-*-12-*-*-*-*-*-*-*" "," "-*-terminus-medium-r-*-*-12-*-*-*-*-*-*-*"; #define NUMCOLORS 12 static const char colors[NUMCOLORS][ColLast][9] = { // border foreground background { "#282a2e", "#999999", "#1d1f21" }, // 1 = normal (grey on black) { "#f0c674", "#ffffff", "#1d1f21" }, // 2 = selected (white on black) { "#dc322f", "#1d1f21", "#f0c674" }, // 3 = urgent (black on yellow) { "#282a2e", "#282a2e", "#1d1f21" }, // 4 = darkgrey on black (for glyphs) { "#282a2e", "#1d1f21", "#282a2e" }, // 5 = black on darkgrey (for glyphs) { "#282a2e", "#cc6666", "#1d1f21" }, // 6 = red on black { "#282a2e", "#b5bd68", "#1d1f21" }, // 7 = green on black { "#282a2e", "#de935f", "#1d1f21" }, // 8 = orange on black { "#282a2e", "#f0c674", "#282a2e" }, // 9 = yellow on darkgrey { "#282a2e", "#81a2be", "#282a2e" }, // A = blue on darkgrey { "#282a2e", "#b294bb", "#282a2e" }, // B = magenta on darkgrey { "#282a2e", "#8abeb7", "#282a2e" }, // C = cyan on darkgrey }; // border foreground background // { "#282a2e", "#373b41", "#1d1f21" }, // 1 = normal (grey on black) // { "#f0c674", "#c5c8c6", "#1d1f21" }, // 2 = selected (white on black) // { "#dc322f", "#1d1f21", "#f0c674" }, // 3 = urgent (black on yellow) // { "#282a2e", "#282a2e", "#1d1f21" }, // 4 = darkgrey on black (for glyphs) // { "#282a2e", "#1d1f21", "#282a2e" }, // 5 = black on darkgrey (for glyphs) // { "#282a2e", "#cc6666", "#1d1f21" }, // 6 = red on black // { "#282a2e", "#b5bd68", "#1d1f21" }, // 7 = green on black // { "#282a2e", "#de935f", "#1d1f21" }, // 8 = orange on black // { "#282a2e", "#f0c674", "#282a2e" }, // 9 = yellow on darkgrey // { "#282a2e", "#81a2be", "#282a2e" }, // A = blue on darkgrey // { "#282a2e", "#b294bb", "#282a2e" }, // B = magenta on darkgrey // { "#282a2e", "#8abeb7", "#282a2e" }, // C = cyan on darkgrey // }; // // static const char normbordercolor[] = "#bbbbbb"; // static const char normbgcolor[] = "#222222"; // static const char normfgcolor[] = "#999999"; // static const char selbordercolor[] = "#005577"; // static const char selbgcolor[] = "#005577"; // static const char selfgcolor[] = "#ffffff"; static const char normbordercolor[] = "#073642"; static const char normbgcolor[] = "#002b36"; static const char normfgcolor[] = "#fdf6e3"; static const char selbordercolor[] = "#586e75"; static const char selbgcolor[] = "#073642"; static const char selfgcolor[] = "#fdf6e3"; static const unsigned int borderpx = 0; /* border pixel of windows */ static const unsigned int snap = 5; /* snap pixel */ static const Bool showbar = True; /* False means no bar */ static const Bool topbar = True; /* False means bottom bar */ /* tagging */ static const char *tags[] = { "Geile Terminals", "2", "3", "4", "RDP", "Windows", "Citrix", "Mail", "Web" }; static const Rule rules[] = { /* class instance title tags mask isfloating monitor */ { "Gimp", NULL, NULL, 0, True, -1 }, { "Xfce4-terminal", NULL, NULL, 0, False, -1 }, { "VirtualBox", "VirtualBox", NULL, 0, True, -1 }, { "Firefox", "Navigator", NULL, 1 << 8, False, -1 }, { "Firefox", "Browser", "Firefox Preferences", 1 << 8, True, -1 }, { "Thunderbird", NULL, NULL, 1 << 7, False, -1 }, { "Thunderbird", "Msgcompose", NULL, 1 << 7, True, -1 }, { "Wfica", NULL, NULL, 1 << 6, True, -1 }, { "xfreerdp", NULL, NULL, 1 << 4, True, -1 }, }; /* layout(s) */ static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ static const int nmaster = 1; /* number of clients in master area */ static const Bool resizehints = True; /* True means respect size hints in tiled resizals */ #include "bstack.c" #include "bstackhoriz.c" static const Layout layouts[] = { /* symbol arrange function */ { "[]=", tile }, /* first entry is default */ { "><>", NULL }, /* no layout function means floating behavior */ { "[M]", monocle }, }; /* key definitions */ #define MODKEY Mod1Mask #define TAGKEYS(KEY,TAG) \ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, /* helper for spawning shell commands in the pre dwm-5.0 fashion */ #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } /* commands */ static const char *dmenucmd[] = { "dmenu_run", "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL }; static const char *termcmd[] = { "gnome-terminal", 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, XK_q, 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} }, }; /* button definitions */ /* click can be ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ static Button buttons[] = { /* click event mask button function argument */ { ClkLtSymbol, 0, Button1, setlayout, {0} }, { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, { ClkWinTitle, 0, Button2, zoom, {0} }, { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, { ClkClientWin, MODKEY, Button1, movemouse, {0} }, { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, { ClkTagBar, 0, Button1, view, {0} }, { ClkTagBar, 0, Button3, toggleview, {0} }, { ClkTagBar, MODKEY, Button1, tag, {0} }, { ClkTagBar, MODKEY, Button3, toggletag, {0} }, };
X Session
Create a .desktop file so you can choose dwm from the gdm greeter. /usr/share/xsessions/dwm.desktop
[Desktop Entry] Name=dwm Comment=The dwm tiling window manager Exec=/usr/local/bin/dwm-wrapper # no icon yet, only the top three are currently used Icon= Type=Application
dwm-wrapper
The .desktop file will call the dwm-wrapper, which sets the top menu bar. /usr/local/bin/dwm-wrapper
#! /bin/sh # setxkbmap -option terminate:ctrl_alt_bksp # feh --bg-scale /home/shaun/img/arch.png # conky -x 0 -y 0 -d # Colour codes from dwm/config.h colour_gry="\x01" # grey on black colour_wht="\x02" # white on black colour_dgry="\x04" # darkgrey on black colour_blk="\x05" # black on darkgrey colour_red="\x06" # colour_red on black colour_grn="\x07" # green on black colour_dylw="\x08" # orange on black colour_ylw="\x09" # yellow on black colour_blu="\x0A" # colour_blue on darkgrey colour_mag="\x0B" # colour_magenta on darkgrey colour_cyn="\x0C" # cyan on darkgrey # Icon glyphs from font xbmicons.pcf glyph_msc="\uE00E" glyph_cpu="\uE00F" glyph_mem="\uE010" glyph_dl="\uE011" glyph_ul="\uE012" glyph_com="\uE013" glyph_eml="\uE014" glyph_vol="\uE015" glyph_tim="\uE016" glyph_tor="\uE017" sep_solid="\uE01A" sep_line="\uE01B" sep_bar="\uE020" print_mem_used() { mem_used="$(free -m | awk 'NR==3 {print $3}')" echo -ne "${sep_line} ${glyph_mem} ${mem_used}M " } print_volume() { volume="$(amixer get IEC958 | tail -n1 | sed -r 's/.*\[(.*)%\].*/\1/')" echo -ne "${colour_dgry}${sep_solid}${colour_mag} ${glyph_vol} ${volume}% " } print_datetime() { datetimeloc="$(date "+%A %d.%m.%Y %Z=%H:%M")" datetimeusc="$(TZ=US/Central date "+%Z=%H:%M")" datetime="$(date "+%a %d %b ${sep_line} %H:%M")" echo -ne "${colour_blk}${sep_solid}${colour_wht} ${glyph_tim} ${datetimeloc} ${datetimeusc}" } rx_old=$(cat /sys/class/net/em1/statistics/rx_bytes) tx_old=$(cat /sys/class/net/em1/statistics/tx_bytes) while true; do # get new cpu idle and total usage eval $(awk '/^cpu /{print "cpu_idle_now=" $5 "; cpu_total_now=" $2+$3+$4+$5 }' /proc/stat) cpu_interval=$((cpu_total_now-${cpu_total_old:-0})) # calculate cpu usage (%) let cpu_used="100 * ($cpu_interval - ($cpu_idle_now-${cpu_idle_old:-0})) / $cpu_interval" # get new rx/tx counts rx_now=$(cat /sys/class/net/em1/statistics/rx_bytes) tx_now=$(cat /sys/class/net/em1/statistics/tx_bytes) # calculate the rate (K) and total (M) let rx_rate=($rx_now-$rx_old)/1024 let tx_rate=($tx_now-$tx_old)/1024 # let rx_total=$rx_now/1048576 # let tx_total=$tx_now/1048576 # output vars print_cpu_used() { printf "%-14b" "${colour_dgry}${sep_solid}${colour_blu} ${glyph_cpu} ${cpu_used}%" } print_rx_rate() { printf "%-15b" "${colour_blk}${sep_solid}${colour_grn} ${glyph_dl} ${rx_rate}K" } print_tx_rate() { printf "%-14b" "${colour_gry}${sep_line}${colour_red} ${glyph_ul} ${tx_rate}K" } # Pipe to status bar, not indented due to printing extra spaces/tabs xsetroot -name "$(print_cpu_used)$(print_mem_used)\ $(print_rx_rate)$(print_tx_rate)\ $(print_volume)\ $(print_datetime)" # reset old rates rx_old=$rx_now tx_old=$tx_now cpu_idle_old=$cpu_idle_now cpu_total_old=$cpu_total_now # loop stats every 1 second sleep 1s done & /bin/xset fp+ /usr/share/fonts/terminus & /bin/xset fp+ /usr/share/fonts/terminus2 & /bin/xset fp+ /usr/share/fonts/xbmicons_pcf & /bin/xset fp rehash & /usr/local/bin/feh --bg-scale /usr/share/backgrounds/funeral.jpg & /bin/sleep 1; /bin/xset dpms force off & /bin/xrandr --output DP2 --rotate left exec /usr/local/bin/dwm
.Xresources
In my .Xresources, I'm setting the UXTerm color to white on black, as well as fixing a bug with the Alt key in SSH sessions. The last line is to set the window URGENT flag when the window uses the system bell.
UXTerm*eightBitInput: false UXTerm*metaSendsEscape: true UXTerm*reverseVideo: true UXTerm*bellIsUrgent: true
Tweaking dwm
Rules
What does ‘rules’ do?
The rules array allows to treat certain applications (clients) in a special way. A rule has a matching and an action part. When a new client appears (sends a maprequest), it is matched against the rules based on its class, instance (WM_CLASS) and title (WM_NAME) properties and then the given tag and floating mode setting actions are performed. The default tag mask is 0, which means the currently viewed tags, and the default mode is tiled so isfloating is False. Example from the default config:
static Rule rules[] = { /* class instance title tags mask isfloating monitor */ { "Gimp", NULL, NULL, 0, True, -1 }, { "Firefox", NULL, NULL, 1 << 8, True, -1 }, };
These rules make every Gimp and Firefox window floating and makes Firefox windows appear on tag 9 instead of the currently viewed tags.
How does the matching work?
A client is matched if its properties contain the given strings as substrings (case-sensitively) or NULL is given (which means anything is matched there). More than one rule can be applied to a client, the rules are matched in order.
How to check these properties of a client?
The xprop utility can be used to get this information: WM_CLASS is (instance, class) WM_NAME (or _NET_WM_NAME) is the title. For example this shell script prints the relevant properties of the selected client (if the properties does not contain ‘=’ or ‘,’):
xprop |awk ' /^WM_CLASS/{sub(/.* =/, "instance:"); sub(/,/, "\nclass:"); print} /^WM_NAME/{sub(/.* =/, "title:"); print}'
Hints and Tips
Battery status
upower -i /org/freedesktop/UPower/devices/battery_BAT0 | grep 'percentage' | sed -r 's/^\s*percentage:\s*([0-9]*)\.?.*$/bat: \1%/' upower -i /org/freedesktop/UPower/devices/battery_BAT0 | grep 'state' | awk '{print $2}'