January 22nd 2018

Play Youtube (and many other) Media Links from your Browser with One Click


Requirements

  • Install mpv on your computer.

  • Install youtube-dl on your computer. More about that later.

  • Install the Open With addon. It seems to be available only for Mozilla browsers, but I'm pretty sure something similar also exists for chromish browsers.

Setup

Now make sure mpv is working with local files.
Regardless of this article, mpv is about the best media (video) player available for Linux.
It will automatically detect if youtube-dl is in your $PATH, and use it to play web URLs.

So now all you have to do is to add an entry to Open With settings to open a link with mpv. Additionally, make sure it appears in the Main context Menu (links).

Platform Independent!

First let me say that youtube-dl can do much more than just download youtube videos! With the technique described in this article, I'm using it on a large number of video sites, soundcloud mixes, bandcamp playlists etc. etc.

It is also available for Windows and OS X, and since mpv is also available for Windows and OS X, this How-To is platform independent!!!

About youtube-dl

While it might be in some distros' repositories, it is better to install & update it manually, because most media sites' API changes are addressed and fixed near-immediately, much faster than any distro developer could react.

For some, it might be best to use the github repo, others might simply want to download the latest version. In both cases, the best way to add it to your $PATH is to make a symlink to the executable.

Supposing $HOME/bin is in your $PATH:

$ ln -s /path/to/youtube-dl-newest-version/youtube-dl ~/bin/

You only have to do this once.

If you are not using the github repo, you can regularly update the binary itself with youtube-dl -U. Do this any time you get errors with downloading something, then try again.
Disclaimer: I have not tried this method because I'm using the github repo.

PS

Any of the three tools described here are very useful by themselves.

Use youtube-dl to download videos and music for later use. You can tell it to download a specified quality, codec, create a folder structure based on metadata etc. etc.

Use Open With to open images or PDFs etc. in external applications.

Use mpv to play all sorts of stuff directly from the command line. You'll be surprised by its versatility - multiple media files are often detected automatically, so it plays them one after the other, to only mention one thing. DVDs' contents are usually interpreted correctly, so it starts playing the feature film immediately.
I could go on and on.

August 6th 2016

19 Window Managers


Linux is somewhat famous for having so many different winddowmanagers; this is not a complete list.
My interest was in those that

  • typically run in a standalone session (not as part of a desktop environment, like e.g. mutter for gnome)
  • are somewhat maintained, not too obscure or specialized

I also have a special interest in those that can do both floating and tiling, but not all windowmanagers presented here fulfil that.

The screenshot gallery provides only a very quick overview: what you would be presented with after succesfully starting them for the first time. It does not "show off" the windowmanager's beauty and/or functionality.

Gallery thumb
You have to admire vtwm's ugliness.

I have explored some windowmanagers deeper; you can find links to those articles here:

  1. fluxbox
  2. dwm
  3. twm

Tested on Arch Linux, August - November 2016
This article now has an accompanying forum thread.
It is also inspired by this older forum thread.

Starting the window managers

After you installed the window manager(s), log out.
If you use a display/login manager, you might be able to choose different sessions, and with a little bit of luck your window manager of choice already provides one. If not, follow these instructions.

If you start X via ~/.xinitrc, here are some helpful snippets:

add this to ~/.bash_profile (might be ~/.profile on some systems, but this snippet includes bashisms):
The only bit you might want to edit is the array of window manager executables in the first line. Even so, each entry is tested with which before presenting it as a choice.

Xsessions=(awesome blackbox bspwm cwm dwm echinus fluxbox fvwm herbstluftwm i3 \
jbwm lwm notion openbox pekwm qtile spectrwm twm vtwm)
choices=()

echo "Available Xsessions:"

for (( i=0 , j=1 ; i<${#Xsessions[@]} ; i++ )); do
  if which "${Xsessions[i]}" >/dev/null 2>&1; then
    choices=( ${choices[@]} ${Xsessions[i]} )
    tput setaf $((j%6 + 1 ))
    echo -e "$((j++))\t${Xsessions[i]}"
  fi
done
tput setaf $((j%6 + 1 ))
echo -e "Ctrl+C\tcommand line"
tput sgr0

key=-1
while (( key > ${#choices[@]} )) || (( key <= 0 )) ; do
    read -p "Enter choice: " key
done

if (( key != 0 )) ; then
    echo "$key: ${choices[$((--key))]}"
    export XSESSION="${choices[key]}"
    [[ -z $DISPLAY ]] && sx
fi

then add this to ~/.xinitrc:

xsetroot -solid "#221111"
xterm &
exec $XSESSION > ${XSESSION}log 2>&1

I recommend starting an xterm (or some other terminal) before the window manager, because it won't always be easy to start one during the session. Not all window managers handle Keyboard shortcuts (!) and even so, the keys or mouseclicks required differ. Try opening a terminal with Win+Enter or Alt+Enter or Shift+Alt+Enter. Try clicking on the desktop, left right and middle...

for more in-depth experimenting one could replace the previous snippet with this:

exec $XSESSION > ${XSESSION}log 2>&1 &
# XSESSION defined through user choice in ~/.bash_profile
wm_pid=$!
{
 . $HOME/.config/autostart.sh
} &
wait $wm_pid

this will start the Xsession defined in the previous snippet, and allows you to execute some autostart stuff with any window manager, even those that don't usually support it.

additionally, your ~/.config/autostart.sh could contain sth like this:

# also see ~/.bash_profile
case $XSESSION in
i3)
        stuff &
;;
twm)
        otherstuff &
;;
dwm*)
        morestuff &
;;
*)
        # this will be executed for all wms that are not in the above list;
        # but it will NOT be executed for any of the above!
        stuff &
;;
esac

Once a final (or long-term) decision is made, this should be changed again to a more streamlined startup. Many windowmanagers offer everything that is needed for autostarting applications, no need for additional scripts.

November 12th 2016

TWM Window Manager


twm is historical. It dates back to 1987, and is still being developed (although I think "maintained" would be more appropriate). I simply wanted to try it out and see what I can do with it, if I can customize it to my needs, both in functionality and looks.

Screenshot Gallery

twm thumb

Installation

It's in most Linux distros' repos. If it isn't I honestly don't know what to do. It seems the source is available here.

Usage

Imagine it is 1987. Having a graphical environment at all is a new thing. There's none of those recent "back-to-the-basics" software philosophies - this is the basics. Being able to manage windows must have been amazing.
Placing a new window is a major event. It requires the user's full attention - you have to give it a place on your screen with a click. 30 years later, this seems incredibly annoying. I don't know if the "RandomPlacement" option has been added in later - it does exactly that, and between these two placement policies there's nothing else.

This, and the lack of any sort of virtual desktops, pretty much removes twm from any serious consideration (yes i know there's ways around that, and anyhow the next logical step is to use vtwm - which I will review seperately, soon). Nevertheless I was curious to see what i can do with it - and was surprised how versatile it is otherwise! The minds behind this were not from the stone ages, even if their hardware was (lol emoji here).

I found it pretty easy to get around - you only have to press the left mouse button to get a menu - but if you're confused, you might want to read this post which outlines twm's basic usage. It's worth pointing out that some unusual behaviour can actually be very useful - esp. the fact that I can decide with a click (or hotkey) when a window rises to the top of the stack, regardless of being focused or not. I bound this to a middle click (both on title and window itself), which enables me to quickly click through the windows that are on top of each other.

The idea of "Icons" (which are not small graphic images, but really small rectangles with some text, representing minimized windows) needs some getting used to, especially since there seem to be two approaches:

  • single, independent, more-or-less square icons on the desktop, with some sort of bitmap image representing the minimzed programme (ugly!)
  • an icon manager with rectangles with text, plus a small bitmap image in some cases

both are clickable and clicking them does what one would expect: it restores or iconizes the window.
I opted to remove the bigger, square icons completely and go with the icon manager only, which is comparable to a modern panel.

Configuration

All configuration happens through a single file, usually ~/.twmrc.

To make it short, this resource was invaluable! Especially the Icons and Configs links towards the end of the page. There is also this thread on LinuxQuestions.

After some fiddling I was able to get good mouse & keyboard functionality, and remove/replace some of the most annoying "graphical" features (mostly the b/w checkerboard frame around focused windows). A lot more is possible, if one wanted to go that way! Keybinds, custom functions for window placement/movement/resizing, the whole lot. The config file cannot include more config files (e.g. a seperate menu file), but there are ways to script around that.
On debian systems a classical debian menu is part of the default root menu.

I was not able to change "Focus follows Mouse" to "Click to Focus", although some comments suggest that this is possible. That's another big no-no for me.

My most recent config


############################################################################
# Font Section
############################################################################
#ResizeFont "*new century schoolbook-medium-i-*--24-*-iso8859-*"
IconManagerFont "-*-terminusv-medium-*-condensed-*-12-*-*-*-*-*-*-*"
MenuFont    "-*-terminusv-bold-*-condensed-*-12-*-*-*-*-*-*-*"
TitleFont   "-*-terminusv-bold-*-condensed-*-12-*-*-*-*-*-*-*"
IconFont    "-*-terminusv-bold-*-condensed-*-12-*-*-*-*-*-*-*"
# font: http://dt.iki.fi/terminusv

############################################################################
# Variables Section
############################################################################
#
# TWM Boolean Variables
#
AutoRelativeResize  # Allow resize from any point within the window
#ClientBorderWidth  # Take border width from initial border width of window
DecorateTransients  # Transient windows should have titlebars
DontMoveOff     # Do not allow windows to be moved of the screen
ForceIcons      # Force use of "Icons" list instead of client-supplied one
NoBackingStore  # Backing store for twm's menus
NoCaseSensitive     # For sorting icon names in icon manager
NoDefaults      # Needed when building own title buttons and bindings
NoGrabServer        # When popping up menus or moving opaque windows
NoMenuShadows       # Don't draw drop shadows behind menus
#NoRaiseOnMove      # Don't automatically raise when windows are moved
#NoRaiseOnResize        # Don't automatically raise when windows are resized
# NoRaiseOnWarp     # Don't automatically raise window when f.warpto
# NoSaveUnders      # Repaint instead of save-under for menu selection
#NoTitleFocus       # Don't set input focus when window is entered
OpaqueMove      # F.move window instead of just an outline
RandomPlacement     # Don't give ouline-drag for no-geometry windows
RestartPreviousState    # 'Remember' previous state when window manager is restarted
ShowIconManager     # Show icon manager on startup
SortIconManager     # Sort icons alphabetically in iconmanager
WarpUnmapped        # Allow f.warpto to de-iconify windows

#
# TWM Numeric Variables
#
MenuBorderWidth     1
BorderWidth     2   # Frame border width in pixels
ButtonIndent        0   # 0, Title button indentation in pixels
ConstrainedMoveTime 400 # Time (msec) in which double click allows only move in hor or vert direction
FramePadding        2   # Pixelwidth between titlebar decorations and the window frame
IconBorderWidth     2   # Border of icons in pixels
MoveDelta       3   # Number of pixels to move before f.move starts working (also f.deltastop)
TitleButtonBorderWidth  1   # 0, Distance between title buttons
TitlePadding        8   # 16, Distance between title buttons, text and highlight area

#
# TWM String Variables
#
# Path to look for bitmaps if they cannot be found in "bitmapFilePath" resource
IconDirectory       "/usr/include/X11/bitmaps"
IconDirectory       "~/.config/twm/icons"
UsePPosition        "on"        # program requested location, "on" "off" "nonzero"

# TWM Complex Variables
#
IconManagerGeometry "=160x10-0+0" 1
# Define regions to put icons (multiple lines allowed)
# IconRegion    geomstring  # define geometry)
#       vgrav       # North or South fill direction
#       hgrav       # East for West fill direction
#       gridwidth   # grid dimensions to put icons in
#       gridheight
IconRegion      "=300x300+200-0" North East 30 30

Color
{
    #DefaultBackground "#222222"
    #DefaultForeground "#bbbbbb"
    TitleBackground "#222222"
    TitleForeground "#bbbbbb"
    MenuBackground "#222222"
    MenuForeground "#bbbbbb"
    MenuBorderColor "#666666"
    MenuTitleBackground "#bbbbbb"
    MenuTitleForeground "#222222"
    BorderColor "#005577"
    IconBackground "#222222"
    IconForeground "#999999"
    IconBorderColor "#999999"
    IconManagerBackground "#222222"
    IconManagerForeground "#bbbbbb"
    IconManagerHighlight "#005577"
    BorderTileBackground "#666666"
    BorderTileForeground "#666666"
}

Cursors {
    # cursorname    "string" for names in include/X11/cursorfont.h
    # cursorname    "image" "mask" for cursors taken from bitmap files
    Frame       "top_left_arrow"    # "spider"
    Title       "top_left_arrow"
    Icon        "top_left_arrow"
    IconMgr     "top_left_arrow"
    Move        "fleur"
    Resize      "fleur"
    Menu        "sb_left_arrow"
    Button      "hand2"
    Wait        "watch"
    Select      "dot"
    Destroy     "pirate"
}

DontIconifyByUnmapping {
    "Xjewel"
}
IconifyByUnMapping

IconManagerDontShow {
#   "names of things which you don't want to see in the icon manager"
    "oclock"
    "xcpustate"
    "xdaliclock"
    "Xman"
    "xmeter"
    "xpbiff"
    "TWM Icon Manager"
    "xload"
    "xeyes"
    "xclock"
}

IconManagers {          # Definition of iconmanagers...
    # "winname" ["iconname"]    "geometry"  columns
    # "XTerm"           "=300x5+800+5"  5
}

#ForceIcons
Icons {
#   "name"  "name.icon"
    "xterm" "terminal"
    "URxvt" "terminal"
}

NoHighlight {
    "TWM Icon Manager"
}

NoStackMode { }     # ignore stacking request for these windows

# MakeTitle { } # Create title bars even when NoTitle has been specified
NoTitle {
#   "names of things for which you don't want a title bar"
    "oclock"
    "swissclock"
    "swisswatch"
    "TWM Icon Manager"
    "xcb"
    "xcmap"
    "xcpustate"
    "xdaliclock"
    "xeyes"
    "Xman"
    "xmeter"
    "xpbiff"
    "xpostit"
    "xload"
    "xclock"
}

#~ NoTitleHighlight # don't highlight titlebar when focused in window
Pixmaps {
    # TitleHighlight    "hlines2"
    TitleHighlight  "dimple3" # better than notitlehighlight
}

StartIconified  {
#    "console"
}

WarpCursor {        # warp cursor in window when de-iconified
#    "xterm"
}

WindowRing {        # windows to cycle through by f.warpring
#    "xterm"
}

######################################################################
# FUNCTIONS
######################################################################
Function "dmenu_run_hist" {
f.exec "exec dmenu_run_hist -fn 'terminusv:style=bold' -nb '#222222' -nf '#bbbbbb' -sb '#005577' -sf '#dddddd' "
}

Function "pacmenu" {
f.exec "exec pacmenu -l 'dmenu -fn 'terminus:size=9' -nb '#222222' -nf '#bbbbbb' -sb '#005577' -sf '#dddddd' -l 33' "
}

######################################################################
# Titlebuttons
######################################################################
# bitmaps are stored in /usr/include/X11/bitmaps
# ":bitmap" uses internal bitmap
#         (:dot, :xlogo, :iconify, :resize, :question, :delete, :menu)
#---------------------------------------------------------------------
RightTitleButton    "minimize2" = f.iconify
# RightTitleButton  ":menu"     = f.menu "WindowSettings"
RightTitleButton    ":resize"   = f.resize
RightTitlebutton    "close2"    = f.delete

#Button = KEYS : CONTEXT : FUNCTION
#----------------------------------
Button1 =      : root   : f.menu "rootmenu"
Button3 =      : root   : f.menu "TwmWindows"
Button2 =      : root   : f.menu "othermenu"

Button2 =      : window|title  : f.raiselower
Button1 =      : title  : f.move
Button3 =      : title  : f.menu "titlemenu"

Button2 =      : frame  : f.raiselower
Button1 =      : frame  : f.move
Button3 =      : frame  : f.menu "rootmenu"

Button2 =      : iconmgr  : f.delete
Button1 =      : iconmgr  : f.iconify
Button3 =      : iconmgr  : f.iconify

"Tab"   = m | s : all           : f.backiconmgr
"Tab"   = m     : all           : f.forwiconmgr
"Tab"   = m | s : all           : f.upiconmgr
"Tab"   = m     : all           : f.downiconmgr

"Return" = s : all : f.function "dmenu_run_hist"
"Return" = s | c : all : f.function "pacmenu"
"F4" = m : all : f.destroy
"q" = m4 : all : f.destroy
"d" = m : all : f.function "dmenu_run_hist"
"r" = c | m : all : f.restart
"q" = s | m4 : all : f.quit
"t" = m4 : all : f.exec "exec my term"

#
# And a menu with the usual things
#
menu "rootmenu"
{
"Twm"   f.title
"Show Iconmgr"  f.showiconmgr
"Hide Iconmgr"  f.hideiconmgr
"

January 1st 2017

The Fluxbox Windowmanager


This article is part of a series.

due to loss of data, links to downloads from my own site don't work, but I'm hoping to recover most of it soon.

I still managed to find the old Fluxbox web page (or here) from ~2002:
Old fluxbox site
How nice is that!

What fascinates me about Fluxbox is its history. It has developed from blackbox around 2001, is still actively developed and has a devoted user base. In its early days it must have been the number one alternative window manager / desktop environment for all the leet & stylish linux hackers.
Maybe even more important than its history is its continued compatibility with itself; you can still use themes from the earliest days (even blackbox themes, to some xtent)! Random example, one of tenner's creations:
old tenner theme

So we have a lot of heritage to work through. Ambitious side projects to make it into a full but lightweight desktop environment mostly came to a standstill, but are still maintained or at least hosted by enthusiasts (I presume).

Fluxbox, as it is now, seems to be concentrating more on being a good window manager, and leave utilities to third parties. It has a lot of good features, but also some that are better left unused or are in dire need of revision & improvement. My opinion of course.
On the other hand, it is designed with the idea of using it as a standalone desktop environment; there's a startup file, hotkeys are managed, menus are configurable, themes include backgrounds (see below, fluxbox utilizes both fbsetbg and fbroot automatically. and fbroot's mod patterns are something to play with! so retro!) and font definitions, a panel with a systray is included, fake transparency is possible, real transparency works with an external compositor, etc. etc. And all configuration is done through easily editable plain text files in ~/.fluxbox. That's what I call user centric.

Installation

Fluxbox is in practically all Linux distros' repositories. Installation should be trivial.

Version installed and tested: Fluxbox 1.3.7 : (c) 2001-2015 Fluxbox Team on Arch Linux.

I don't know if it comes with a session file; probably not. If you don't use a login/display manager, you can use the method described here to launch fluxbox with your Xorg session.

After first login you should be presented with a bottom panel (incl. a systray) and a right-click menu.
If I remember correctly, fluxbox creates the ~/.fluxbox folder and fills it with all config files necessary, with sane defaults.

Usage, Configuration etc.

Fluxbox comes with a few utilities:

/usr/bin/fbrun
/usr/bin/fbsetbg
/usr/bin/fbsetroot
/usr/bin/fluxbox
/usr/bin/fluxbox-generate_menu
/usr/bin/fluxbox-remote
/usr/bin/fluxbox-update_configs
/usr/bin/startfluxbox

fbrun: A simple launcher - too limited for my taste, dmenu_run I use
fbsetbg: a wrapper that searches for a suitable wallpapersetter, I think fluxbox uses this internally, but can be used directly too
fbsetroot: a native wallpaper setter - can also create mod patterns
fluxbox-generate_menu generates menus, but I soon replaced it with trizen's fbmenugen
fluxbox-remote sends commands to a running fluxbox instance, very useful in scripts
fluxbox-update_configs is better left untouched
startfluxbox will start a fluxbox session, but I already have a mechanism in place for that.

If you want to know more, you should start here.
You can find current versions of all man pages there, and that's what I mostly used to configure it. Unfortunately, someone decided to rework the fluxbox wiki, but relied too much on community contributions it seems - the new wiki is practically empty, and as a result most links on fluxbox.org are broken. But you can fix them by prepending old. to the URL, so that fluxbox-wiki.org/... becomes old.fluxbox-wiki.org/....

Manual tiling

This is quite important for me, I must have a few simple keyboard shortcuts to position windows side by side, and the window manager must be able to position newly opened windows intelligently into the remaining space. Fluxbox handles this quite well (but once again the comparison to openbox forces itself upon me, and I must say that openbox handles it better). Just take a look at my keys file; it also contains some more interesting bits & tricks.

Themes a.k.a Styles

Styles are stored in a styles folder and the fluxbox menu has a [stylesdir] directive, so you can apply styles straight from the menu. The style file is called theme.cfg (one of the many little inconsistencies of fluxbox) and for someone who has spent a lot of time with openbox theming the format is easy to grasp. 1

Fluxbox has a big additional feature over openbox - it can use full color pixmaps for almost all styleable areas.
But this feature quickly becomes a non-feature when you examine it:

  • an element's height needs to be precisely the height of the pixmap (I haven't tried what happens if you ignore it, but it will certainly look ugly)
  • transparency is not supported, so one has to carefully style the button pixmaps and other background pixmaps to integrate seamlessly (dude, that is so 2002)

I couldn't accept that I can't just use a simple .xbm to shape a button, like in openbox, so I spent a frustrating hour trying things and reading scattered documentation until I could finally accept it. I hate the looks of the built-in default buttons. I am working on a theme that does not use pixmaps yet reduces the ugliness of the default buttons as much as possible.

Tenr & fluxStyle

So now go and get yourself some themes - I think even the oldest are still compatible, and so you have a huge pile to choose from. I bet your distro has some extra packages, too. If not, just go here and download the two tarballs, and extract to ~/.fluxbox/styles (although you'll soon find that you can put them elsewhere, too).

I applaud the idea of having a special style folder item for the menu, but without previews it is of little use to me. Unfortunately fluxbox does not come with a graphical application to choose styles, like openbox' obconf. There is one very old app called fluxStyle and, cutting the story short, I forked it because it needed some changes to even run on my system. I also added a script that creates preview images according to some unofficial rules and copies the theme around to avoid writing to system directories.

FluxStyle fork, download here

If you use Archlinux, all tenr styles are in the AUR and you can configure your ~/.fluxStyle.rc like this:

# No need to add ~/.fluxbox/styles it is the default location and if it is listed it will
# be ignored.
STYLES_DIRS:Global,/usr/share/fluxbox/styles:tenr 1-100,/usr/share/fluxbox/tenr_styles/1-100:tenr 101-200,/usr/share/fluxbox/tenr_styles/101-200:tenr 201-300,/usr/share/fluxbox/tenr_styles/201-300:tenr 301-400,/usr/share/fluxbox/tenr_styles/301-400

Even Older Stuff

I also found some even older styles here and bunched them together - who knows when that piece of internet and linux history will go down forever...
At the same time I grabbed the old documentation because I noticed that it's not easy getting both up-to-date & complete documentation for fluxbox.

Miscellaneous

Fluxbox has its own pager (that's a workspace switcher) called fbpager - but it sucks, full stop. All other standalone pagers seem to suck also, one way or another: bbpager, ipager, netwmpager...
I managed to get bbpager to work & look fairly good (if it's in the slit, its borders will take the style of the current fluxbox theme), please see the gallery below.
One configuration is included in this theme I modified.
Unfortunately, it behaved strangely when autostarted and I had to revert to this ugly hack in my autostart script:
( bbpager -w > $HOME/.bbtools/bbpager.log 2>&1 & sleep 1; fluxbox-remote restart ) &

Constantly getting this warning?

Warning: Failed to open file(fluxbox.cat)
for translation, using default messages.

It means that your locale is not in /usr/share/fluxbox/nls. Solution:

cd /usr/share/fluxbox/nls
sudo ln -is en_US.UTF-8 $(locale | grep LANG | cut -d= -f2)

Adjust to taste.

Conclusion?

In the beginning I really liked the thought of having a panel (toolbar) as part of the window manager. But fluxbox' toolbar is very limited. most things I can do without, but not a pager.
So in the end, instead of using a separate pager or some other hacky solution, I dropped the toolbar completely2 and went back to my good old tint2 workflow (see gallery below).

Fluxbox has so many good features, and its configurability, its config file structure with its plain format is ideal for a knob twiddler like me (see my enclosed bundled configuration), but some things are just too hacky (e.g. window icons) and, more importantly, have been like that for many years.

I found myself comparing it to Openbox all the time, trying to make it more like openbox. I think I should have a separate round of fluxbox vs. openbox sometime.

Gallery

plugin:page-inject

Downloads


  1. Here is another inconsistency in fluxbox configuration took me hours of wondering. 

  2. Another of these inconsistencies: if you do this from the configuration menu, the systemtray will still be in use, even though it's just not there. You have to disable it in ~/.fluxbox/init:

    session.screen0.toolbar.visible: false
    session.screen0.toolbar.tools: prevworkspace, workspacename, nextworkspace, iconbar, clock <== no tray in this list

November 12th 2016

dwm window manager


I am interested in window managers that can do both tiling and floating layouts. I don't think I'll ever become a tiling purist, but trying out dwm for some longer time has been a good experience.
There's some truth in it - the lack of "features" helps to focus on what's relevant. Both looking at and getting around my dwm desktop has been a pleasant experience (i cannot pretend that looks aren't important at all).

Version tested: dwm-6.1
Disclaimer: some bits of description are copied over from here.

Screenshot Gallery (3 Imgs)

Installation

Because dwm is customized through editing its source code, it’s pointless to make binary packages of it. This keeps its userbase small and elitist. No novices asking stupid questions. (source)

Not very endearing. Still, dwm is packaged in most distros' repositories, and I think it's useful to get a first impression. A default (packaged) dwm desktop can be seen here.
Customisations are made by editing config.h, then compiling. The process is simpler than it sounds! You should try it. Compilation is very fast, dependencies are few, the single binary is very small.
Personally I would be willing to wait a few more µs during startup just to have a normal config file, but this is not a dealbreaker for me, in fact I can see the appeal.

Most people will want to change the default modifier key from left (Mod1) to the Windows key (Mod4). And the default font, and some keybinds. I have not fully explored the possibilities, but in principle everything can be configured.

The border between configuration and programming becomes fluid.

This makes it kind of hard to find complete documentation. the customisation page explains the process and gives a few examples, but for most things there is no complete list of features.
For example: no complete list of all functions that could be accessed with key- or mouse bindings. Of course such a list could never be complete, since you can write your own functions and compile them in!
So any request for complete documentation can always, conveniently, be countered by "Read the code".

But that isn't a crucial problem for me; if I had decided to keep using dwm, there would have been a lot more to explore & configure, maybe with hotkeys and clickable areas (taskbar, statusline, root window...) to start with.

And in any case, I learned something about compiling, the Arch Build System, and patching code with patch and diff along the way.

Usage

In its default configuration, dwm is a very simple tiling window manager. It uses the master-stack model - in tiling mode, starting a new application puts the new app in the "master" area on the left side of the screen, and puts the old "master" app in a tile in the vertical stack on the right side.

Due to dwm's simplicity I was quickly acquainted with the tiling layout and its keybinds; it's all really quite simple, and memorizing just a few keybinds is enough to get around. The workspaces are really layouts, there's 9 of them, plus 0 which means all of them.

Now when you do tiling you start to realise that many applications are really written with floating layouts in mind. Automatic windows resizing, as it happens all the time with tilers, often results in somewhat messed-up UIs: geany's adjustable statusbar might suddenly cover most of the window and I have to drag it down again, to give just one example. But the advantages of tiling are numerous, and maybe in time one would also learn to choose one's applications differently.

No Compliance

There is something called EWMH compliance - without going into detail, it's a set of rules that allows desktop applications (the window manager, some sort of panel, window switcher and the applications themeselves) of UNIX-like operating systems to communicate with each other. This set of rules makes it possible to mix window managers and panels and more-or-less build some sort of custom environment.
Not so with dwm (and many other tiling window managers).
But it doesn't really matter that much; dwm's environment is very much usable - otherwise, what would be the point? But be aware that your favorite panel might become useless, amongst other things.

Apart from that I found out that I can live easily without a system tray or notification area, I use two customized versions of dmenu_run and was trying out rofi as a windows switcher. I was planning to emulate openbox' root menu by binding the rootwindow right-click to a simple, mouse-aware menu application - maybe jgmenu.

Caveats

Nothing is perfect. There are, however, a few things I cannot live with, and the quest for the perfect window manager has to continue.

  • floating is clearly a second class citizen with dwm. Dialog windows are recognized and pop up more-or-less in the center, but in floating mode new windows always open in the top-left corner, there's no placement policy whatsoever. I see no functions (that I could bind to keys or mouse actions) that would help me to, even manually, place the windows side by side, or resize them. I only can resize windows by dragging the right mouse button (with a modifier). That just isn't good enough; I'm loosing ease of use from this lack.

  • Focus Follows Mouse: It's enough to move the pointer into a window to give it focus. I hate it! I like to just flick the mouse out of the way and concentrate on typing and moving about with the keyboard, but this makes it impossible. There's an "option" to enable Click To Focus by commenting out [EnterNotify] = enternotify, from dwm.c - but then I have to click a window twice to give it focus. Not so good either.

  • some applications take 100% cpu when they open a window under dwm. It has something to do with floating (conky with its own window, supertuxkart, virtualbox) but also happens in tiling layouts (extremetuxracer). In all cases the application and the X server are hogging resources together, not dwm, but it doesn't happen in any other window manager.

This last point especially made me leave dwm. I really took some time figuring it out, but could not find anything on the web and relevant forums relating to it. Fearing that the only reply would be "because these applications are broken" I did not want to start a thread myself. ☹

Conclusion

There is some appeal in the minimalism; you don't have many features, but soon realize that those few features are designed and chosen carefully and consciously. If that is what you are looking for, together with great speed and minimal dependencies, dwm is a great choice. I think it is designed to go together with certain applications - vim, dmenu, maybe a few more from the suckless pages. You may need to adjust your software habits to a particular frame of mind.

In other words, forget about graphical menus, icons, eyecandy, cruft in general and use the keyboard more. Embrace the source. I am admittedly only partially in that frame of mind. It's all a matter of degrees. I am not willing to give up playing supertuxkart because my window manager promotes a particular software philosphy.

Comparison

This article is part of another article.
There was a thread on crunchbang forums which inspired me to do something like this myself. You can compare this article with the older dwm article from that thread.
There also is an accompanying forum thread on bunsenlabs forums.

My most recent config.h

/* appearance */
static const char *fonts[] = {
    "ubuntu:style=light:size=11"
};
static const char dmenufont[]       = "ubuntu:style=light:size=11";
static const char rofifont[]       = "monaco 10";
static const char normbordercolor[] = "#444444";
static const char normbgcolor[]     = "#222222";
static const char normfgcolor[]     = "#bbbbbb";
static const char selbordercolor[]  = "#005577";
static const char selbgcolor[]      = "#005577";
static const char selfgcolor[]      = "#eeeeee";
static const unsigned int borderpx  = 2;        /* 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             = 0;        /* 0 means bottom bar */

/* tagging */
static const char *tags[] = { "1 ", "2 ", "3 ", "4 ", "5 ", "6 ", "7 ", "8 ", "9 " };

static const Rule rules[] = {
    /* xprop(1):
     *  WM_CLASS(STRING) = instance, class
     *  WM_NAME(STRING) = title
     */
    /* class          instance        title             tags mask     isfloating   monitor */
    { "Conky",        NULL,           NULL,             0,            False,       -1 },
    { "Thunderbird",  NULL,           NULL,             1 << 8,       False,       -1 },
    { "VirtualBox",   NULL,           NULL,             1 << 2,       True,        -1 },
    { "Gimp",         NULL,           NULL,             1 << 6,       False,       -1 },
    { "Pale moon",    NULL,           NULL,             1 << 7,       False,       -1 },
    { "Firefox",      NULL,           NULL,             1 << 7,       False,       -1 },
};

/* layout(s) */
static const float mfact     = 0.5; /* factor of master area size [0.05..0.95] */
static const int nmaster     = 1;    /* number of clients in master area */
static const int resizehints = 0;    /* 1 means respect size hints in tiled resizals */

static const Layout layouts[] = {
    /* symbol     arrange function */
    { "[T]",      tile },    /* first entry is default */
    { "[F]",      NULL },    /* no layout function means floating behavior */
    { "[M]",      monocle },
};

/* key definitions */
#define MODKEY Mod4Mask
#define TAGKEYS(KEY,TAG) \
    { MODKEY,                       KEY,      view,           {.ui = 1 << TAG} }, \
    { MODKEY|ControlMask,           KEY,      toggleview,     {.ui = 1 << TAG} }, \
    { MODKEY|ShiftMask,             KEY,      tag,            {.ui = 1 << TAG} }, \
    { MODKEY|ControlMask|ShiftMask, KEY,      toggletag,      {.ui = 1 << TAG} },

/* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }

/* commands */
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
static const char *dmenucmd[] = { "dmenu_run_hist", "-m", dmenumon, "-fn", dmenufont, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };
static const char *pacmenucmd[] = { "pacmenu", "-m", dmenumon, "-fn", rofifont, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };
static const char *rofiswitcher[] = { "rofi", "-font", rofifont, "-show", "window", NULL };
static const char *termcmd[]  = { "urxvt", NULL };
static const char *conkyweather[]  = { "/home/data/mygit/conky-itl-weather/startconky", "--toggle", "config/noto2.cfg", NULL };
static const char *conkykeys[]  = { "/home/user/.config/conky/keybinds/toggle", NULL };

static Key keys[] = {
    /* modifier                     key        function        argument */
    { MODKEY,                       XK_Return, spawn,          {.v = termcmd } },
    { ShiftMask,                    XK_Return, spawn,          {.v = dmenucmd } },
    { ControlMask|ShiftMask,        XK_Return, spawn,          {.v = pacmenucmd } },
    { ControlMask|Mod1Mask,         XK_w,      spawn,          {.v = conkyweather } },
    { 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|ShiftMask,             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} },
    { Mod1Mask,                     XK_Tab,    spawn,          {.v = rofiswitcher } },
};

/* 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,         Mod1Mask,       Button1,        movemouse,      {0} },
    { ClkClientWin,         Mod1Mask,       Button2,        togglefloating, {0} },
    { ClkClientWin,         Mod1Mask,       Button3,        resizemouse,    {0} },
    { ClkTagBar,            0,              Button1,        view,           {0} },
    { ClkTagBar,            0,              Button3,        toggleview,     {0} },
    { ClkTagBar,            Mod1Mask,       Button1,        tag,            {0} },
    { ClkTagBar,            Mod1Mask,       Button3,        toggletag,      {0} },
};

Additionally, I also patched dwm.c to enable Click To Focus and make the taskbar a little higher:

--- src/dwm-6.1/dwm.c   2015-11-09 00:39:37.000000000 +0200
+++ .patches/dwm.c  2016-11-13 22:52:42.027370610 +0200
@@ -250,3 +250,3 @@
    [DestroyNotify] = destroynotify,
-   [EnterNotify] = enternotify,
+   //[EnterNotify] = enternotify,
    [Expose] = expose,
@@ -1562,3 +1562,3 @@
        die("no fonts could be loaded.\n");
-   bh = drw->fonts[0]->h + 2;
+   bh = drw->fonts[0]->h + 6;
    updategeom();