TWM Window Manager

twm is historical. It dates back to 1987, and is still maintained. I 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.

twm thumbclick me!

Installation

It's in most Linux distros' repos. If it isn't, the source is available here. Compiling it shouldn't be hard.

Usage

Look at the windowmanagers article which has a general description of how to start a simple window manager session.

After succesfully starting the session

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 (although there is ways around that restriction, and maybe the next logical step would be to use vtwm anyhow). Nevertheless I was curious to see what i can do with it - and was surprised how versatile it is otherwise.

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 (almost) comparable to a modern panel.

Startup

You have to use the general method described here.

Here are some snippets you can add:

sh
clipit -n & # both clipit and parcellite have a -n (no systray) option xsetroot -cursor_name left_ptr xeyes -geometry 160x76-0-274 -fg "#222222" -center "#bbbbbb" -outline "#222222" & ( sleep 4 ; xclock -norender -highlight grey -geometry 160x160-0-0 -padding 2 &\ xload -hl red -jumpscroll 1 -nolabel -update 1 -geometry 160x100-0-162 & ) &

Resources

This resource was invaluable. Especially the Icons and Configs links towards the end of the page. There is also this thread on LinuxQuestions.

Recently (April 2020) I also found this.

Configuration

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

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

sh
############################################################################ # 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: 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 }