diff --git a/apelsin.cabal b/apelsin.cabal
--- a/apelsin.cabal
+++ b/apelsin.cabal
@@ -1,16 +1,18 @@
 Name:                   apelsin
-Version:                1.2
+Version:                1.2.1
 Author:                 Christoffer Öjeling
 Maintainer:             christoffer@ojeling.net
 License:                GPL-3
 License-File:           LICENSE
 Category:               Network
 Synopsis:               Server and community browser for the game Tremulous
-Description:            A gtk2hs server and clan browser for the open source game Tremulous <http://tremulous.net>.
-                        Both Tremulous 1.1 and GPP are supported.
-			.
-                        Features filtering, player search, a list of online clan members, a clan list and basic perferences.
+Description:
+  A gtk2hs server and clan browser for the open source game Tremulous
+  <http://tremulous.net>. Both Tremulous 1.1 and GPP are supported.
 
+  Features filtering, player search, a list of online clan members,
+  a clan list and basic perferences.
+
 Cabal-Version:          >= 1.10
 Build-Type:             Simple
 Data-Dir:               share
@@ -23,7 +25,7 @@
                         icons/hicolor/24x24/apps/apelsin.png
                         icons/hicolor/64x64/apps/apelsin.png
 
-Tested-With:            GHC==7.0.3
+Tested-With:            GHC==7.6.1
 
 
 Flag relativePath
@@ -32,16 +34,19 @@
 
 Executable apelsin
   Default-Language:     Haskell2010
-  Default-Extensions:   BangPatterns NamedFieldPuns RecordWildCards
-                        ScopedTypeVariables OverloadedStrings TupleSections GADTs
+  Default-Extensions:   BangPatterns NamedFieldPuns RecordWildCards GADTs
+                        ScopedTypeVariables OverloadedStrings TupleSections
+
   Other-Extensions:     CPP StandaloneDeriving
+
   Build-Depends:        base>=4.3&&<5, array, mtl, containers, transformers,
                         bytestring, directory, filepath, HTTP, network,
-                        tremulous-query>=1.0.5, gtk, glib, process, deepseq
+                        tremulous-query>=1.0.6, gtk, glib, process, deepseq,
+                        cpphs, xdg-basedir
+
   Hs-Source-Dirs:       src
   Main-is:              Apelsin.hs
-  Other-Modules:        System.Environment.XDG.BaseDir
-                        GtkExts
+  Other-Modules:        GtkExts
                         About
                         AutoRefresh
                         ClanFetcher
@@ -68,7 +73,8 @@
                         OnlineClans
                         Paths_apelsin
 
-  Ghc-Options:          -Wall -threaded -fno-warn-unused-do-bind -funbox-strict-fields
+  Ghc-Options:          -Wall -threaded -fno-warn-unused-do-bind
+                        -funbox-strict-fields -optP --cpp -pgmP cpphs
 
   if !flag(relativePath)
     cpp-options:        -DCABAL_PATH
diff --git a/src/About.hs b/src/About.hs
--- a/src/About.hs
+++ b/src/About.hs
@@ -14,7 +14,7 @@
 		, windowTransientFor	:= win
 		, aboutDialogProgramName:= programName
 		, aboutDialogVersion	:= showVersion version
-		, aboutDialogCopyright	:= "Copyright © 2011\nChristoffer Öjeling <christoffer@ojeling.net>"
+		, aboutDialogCopyright	:= "Copyright © 2011-2012\nChristoffer Öjeling <christoffer@ojeling.net>"
 		, aboutDialogComments	:= "A tremulous server and community browser\nLicense: GPLv3"
 		, aboutDialogWebsite	:= "http://ojeling.net"
 		]
diff --git a/src/Apelsin.hs b/src/Apelsin.hs
--- a/src/Apelsin.hs
+++ b/src/Apelsin.hs
@@ -86,8 +86,8 @@
 
 	-- save the current window size and pane positon on exit
 	on win deleteEvent $ tryEvent $ liftIO $ do
-		Config {autoGeometry} <- readMVar (mconfig bundle)
-		when autoGeometry $ do
+		Config {restoreGeometry} <- readMVar (mconfig bundle)
+		when restoreGeometry $ do
 			file		<- inCacheDir "windowsize"
 			(winw, winh)	<- windowGetSize win
 			ppos		<- panedGetPosition pane
@@ -108,7 +108,7 @@
 	widgetShowAll leftView
 
 	-- Restore the window size and pane position
-	when (autoGeometry config) $ ignoreIOException $ do
+	when (restoreGeometry config) $ ignoreIOException $ do
 		file	<- inCacheDir "windowsize"
 		fx	<- readFile file
 		whenJust (mread fx) $ \(winw::Int, winh, ppos::Int) -> do
diff --git a/src/AutoRefresh.hs b/src/AutoRefresh.hs
--- a/src/AutoRefresh.hs
+++ b/src/AutoRefresh.hs
@@ -14,7 +14,7 @@
 data State = Running !ThreadId | Paused | Stopped
 
 autoSignal :: MVar AutoSignal -> AutoSignal -> IO ()
-autoSignal m = putMVar m
+autoSignal = putMVar
 
 autoRunner :: MVar AutoSignal -> MVar Config -> IO a -> IO ThreadId
 autoRunner m mconfig refreshAction = forkIO $ go Stopped Nothing
@@ -54,7 +54,7 @@
 
 startAuto :: MVar Config -> Maybe MicroTime -> IO a -> IO ThreadId
 startAuto mconfig lastRefresh refreshAction = uninterruptibleMask $ \restore -> forkIO $ do
-		delay <- autoDelay <$> readMVar mconfig
+		delay <- autoRefreshDelay <$> readMVar mconfig
 		whenJust lastRefresh $ \past -> do
 			now <- getMicroTime
 			when (past+delay > now) $
diff --git a/src/Clanlist.hs b/src/Clanlist.hs
--- a/src/Clanlist.hs
+++ b/src/Clanlist.hs
@@ -50,15 +50,15 @@
 
 	addColumnFS gen "_Name" False (Just $ comparing $ name . fst)
 		(rememberColumn bundle 1)
-		cellRendererTextNew [] (simpleColumn (original . name))
+		fastCellTextRenderer [] (simpleColumn (original . name))
 
 	addColumnFS gen "_Tag" False (Just $ comparing $ tagexpr . fst)
 		(rememberColumn bundle 2)
-		cellRendererTextNew [] (markupColumn (prettyTagExpr . tagexpr))
+		fastCellTextRenderer [] (markupColumn (prettyTagExpr . tagexpr))
 
 	addColumnFS gen "Website" False Nothing
 		(const (return ()))
-		cellRendererTextNew [] $ \rend (Clan{..},_) -> do
+		fastCellTextRenderer [] $ \rend (Clan{..},_) -> do
 			set rend $ if websitealive
 				then [ cellTextStrikethrough := False, cellTextUnderline := UnderlineSingle, cellTextForegroundColor := Color 0 0 maxBound ]
 				else [ cellTextStrikethrough := True, cellTextUnderline := UnderlineNone, cellTextForegroundColor := Color maxBound 0 0 ]
@@ -66,10 +66,10 @@
 
 	addColumnFS gen "IRC" False Nothing
 		(const (return ()))
-		cellRendererTextNew [] (simpleColumn irc)
+		fastCellTextRenderer [] (simpleColumn irc)
 
 	Config{..} <- readMVar mconfig
-	treeSortableSetSortColumnId sorted clanlistSort clanlistOrder
+	treeSortableSetSortColumnId sorted clanlistSortColumn clanlistOrder
 
 
 	treeModelFilterSetVisibleFunc filtered $ \iter -> do
@@ -85,7 +85,7 @@
 
 		when (title == Just "Website" && (not . B.null) website) $ openInBrowser $
 			if websitealive then B.unpack website
-					else "http://wayback.archive.org/web/*/" ++ (B.unpack website)
+					else "http://wayback.archive.org/web/*/" ++ B.unpack website
 
 		when active $ whenJust clanserver $ \server -> do
 			P.PollResult{..} <- readMVar mpolled
@@ -119,6 +119,6 @@
 rememberColumn Bundle{..} n col = do
 	order <- treeViewColumnGetSortOrder col
 	current <- takeMVar mconfig
-	let new = current {clanlistSort = n, clanlistOrder = order}
+	let new = current {clanlistSortColumn = n, clanlistOrder = order}
 	putMVar mconfig new
 	configToFile parent new
diff --git a/src/Config.hs b/src/Config.hs
--- a/src/Config.hs
+++ b/src/Config.hs
@@ -1,6 +1,14 @@
-module Config (Config(..), ColorTheme, configFromFile, configToFile
-	, makeColorsFromList, RefreshMode(..)
+{-# LANGUAGE CPP #-}
+module Config(
+      Config(..)
+    , ColorTheme
+    , RefreshMode(..)
+    , defaultConfig
+    , configFromFile
+    , configToFile
+    , makeColorsFromList
 ) where
+import Prelude hiding (catch)
 import Graphics.UI.Gtk (SortType(..), Window)
 import Data.Array
 import Data.Char
@@ -20,147 +28,176 @@
 type ColorTheme = Array Int TremFmt
 
 data SortingOrderPretty = Ascending | Descending
-	deriving (Show, Read, Enum)
+    deriving (Show, Read, Enum)
 
 data RefreshMode = Startup | Auto | Manual
-	deriving (Show, Read, Eq)
+    deriving (Show, Read, Eq)
 
 data Config = Config
-	{ masterServers :: ![(String, Int, Int)]
-	, clanSyncURL	:: !String
-	, tremPath
-	, tremGppPath	:: !String
-	, refreshMode	:: !RefreshMode
-	, autoClan
-	, autoGeometry	:: !Bool
-	, autoDelay	:: !MicroTime
-	, filterBrowser
-	, filterPlayers	:: !String
-	, filterEmpty	:: !Bool
-	, browserSort
-	, playersSort
-	, clanlistSort	:: !Int
-	, browserOrder
-	, playersOrder
-	, clanlistOrder	:: !SortType
-	, delays	:: !Delay
-	, colors	:: !ColorTheme
-	}
+    { masterServers         :: ![(String, Int, Int)]
+    , clanlistURL           :: !String
+    , tremulousPath
+    , tremulousGppPath
+    , unvanquishedPath      :: !String
+    , refreshMode           :: !RefreshMode
+    , autoClan
+    , restoreGeometry       :: !Bool
+    , autoRefreshDelay      :: !MicroTime
+    , filterBrowser
+    , filterPlayers         :: !String
+    , showEmpty             :: !Bool
+    , browserSortColumn
+    , playersSortColumn
+    , clanlistSortColumn    :: !Int
+    , browserOrder
+    , playersOrder
+    , clanlistOrder         :: !SortType
+    , delays                :: !Delay
+    , colors                :: !ColorTheme
+    }
 
+defaultConfig :: Config
+defaultConfig = Config
+    { masterServers         = [ ("master.tremulous.net", 30710, 69)
+                              , ("master.tremulous.net", 30700, 70)
+                              , ("unvanquished.net", 27950, 86)
+                              ]
+    , clanlistURL           = "http://ddos-tremulous.eu/cw/api/2/clanlist"
 
+#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
+    , tremulousPath         = "C:\\Program Files\\Tremulous\\tremulous.exe"
+    , tremulousGppPath      = "C:\\Program Files\\Tremulous\\tremulous-gpp.exe"
+    , unvanquishedPath      = "C:\\Program Files\\Unvanquished\\daemon.exe"
+#else
+    , tremulousPath         = "tremulous"
+    , tremulousGppPath      = "tremulous-gpp"
+    , unvanquishedPath      = "unvanquished"
+#endif
+
+    , refreshMode           = Startup
+    , autoClan              = True
+    , restoreGeometry       = True
+    , autoRefreshDelay      = 120000000 -- 120 seconds
+    , filterBrowser         = ""
+    , filterPlayers         = ""
+    , showEmpty             = True
+    , browserSortColumn     = 3
+    , playersSortColumn     = 0
+    , clanlistSortColumn    = 1
+    , browserOrder          = ascending
+    , playersOrder          = ascending
+    , clanlistOrder         = ascending
+    , delays                = defaultDelay
+    , colors                = makeColorsFromList
+                                [ TremFmt False "#000000"
+                                , TremFmt True  "#d60503"
+                                , TremFmt True  "#25c200"
+                                , TremFmt True  "#eab93d"
+                                , TremFmt True  "#0021fe"
+                                , TremFmt True  "#04c9c9"
+                                , TremFmt True  "#e700d7"
+                                , TremFmt False "#000000"
+                                ]
+    }
+    where ascending = (toEnum . fromEnum) Ascending
+
+
+#define NS(x) (showKV x #x)
+#define NSF(x, y) (showKV ((y) x) #x)
 newSave :: Config -> String
 newSave Config{delays=Delay{..}, ..} = unlines $
-	[ f masterServers	mastersText
-	, f clanSyncURL		clanText
-	, f tremPath		t11Text
-	, f tremGppPath		t12Text
-	, f refreshMode		refreshModeText
-	, f autoClan		autoClanText
-	, f autoGeometry	geometryText
-	, f (autoDelay`quot`1000000) autoDelayText
-	, f filterBrowser	browserfilterText
-	, f filterPlayers	playerfilterText
-	, f filterEmpty		showEmptyText
-	, f browserSort		browserSortText
-	, f playersSort		playerSortText
-	, f clanlistSort	clanlistSortText
-	, f (conv browserOrder)	browserOrderText
-	, f (conv playersOrder)	playerOrderText
-	, f (conv clanlistOrder) clanlistOrderText
-	, f packetTimeout	packetTimeoutText
-	, f packetDuplication	packetDuplicationText
-	, f throughputDelay	throughputDelayText
-	] ++
-	zipWith (\a b -> f b (colorText ++ [a])) ['0'..'7'] (elems colors)
-	where
-	conv :: SortType -> SortingOrderPretty
-	conv = toEnum . fromEnum
-	f :: Show v => v -> String -> String
-	f v k = k ++ " " ++ show v
+    [ NS(masterServers)
+    , NS(clanlistURL)
+    , NS(tremulousPath)
+    , NS(tremulousGppPath)
+    , NS(unvanquishedPath)
+    , NS(refreshMode)
+    , NS(autoClan)
+    , NS(restoreGeometry)
+    , NSF(autoRefreshDelay, (`quot`1000000))
+    , NS(filterBrowser)
+    , NS(filterPlayers)
+    , NS(showEmpty)
+    , NS(browserSortColumn)
+    , NS(playersSortColumn)
+    , NS(clanlistSortColumn)
+    , NSF(browserOrder, conv)
+    , NSF(playersOrder, conv)
+    , NSF(clanlistOrder, conv)
+    , NS(packetTimeout)
+    , NS(packetDuplication)
+    , NS(throughputDelay)
+    ] ++ zipWith
+        (\a b -> showKV b ("color" ++ [a])) ['0'..'7']
+        (elems colors)
+    where
+    conv :: SortType -> SortingOrderPretty
+    conv = toEnum . fromEnum
+    showKV :: Show v => v -> String -> String
+    showKV v k = k ++ " " ++ show v
 
+#define NP(x) x <- getKV #x id (x defaultConfig)
+#define NP_NODEF(x) x <- getKV #x id
+#define NPF(x, f) x <- getKV #x (f) (x defaultConfig)
 newParse :: [(String, String)] -> Config
 newParse = evalState $ do
-	masterServers	<- f mastersText		[("master.tremulous.net", 30710, 69), ("master.tremulous.net", 30700, 70)]
-	clanSyncURL	<- f clanText			"http://ddos-tremulous.eu/cw/api/2/clanlist"
-	tremPath	<- f t11Text			defaultTremulousPath
-	tremGppPath	<- f t12Text			defaultTremulousGPPPath
-	refreshMode	<- f refreshModeText		Startup
-	autoClan	<- f autoClanText		True
-	autoGeometry	<- f geometryText		True
-	autoDelay	<- (*1000000) <$> f autoDelayText		120 -- 120s
-	filterBrowser	<- f browserfilterText		""
-	filterPlayers	<- f playerfilterText		""
-	filterEmpty	<- f showEmptyText		True
-	browserSort	<- f browserSortText		3
-	playersSort	<- f playerSortText		0
-	clanlistSort	<- f clanlistSortText		1
-	browserOrder	<- toEnum . fromEnum <$> f browserOrderText	Ascending
-	playersOrder	<- toEnum . fromEnum <$> f playerOrderText	Ascending
-	clanlistOrder	<- toEnum . fromEnum <$> f clanlistOrderText	Ascending
-	packetTimeout	<- f packetTimeoutText	(packetTimeout defaultDelay)
-	packetDuplication<- f packetDuplicationText	(packetDuplication defaultDelay)
-	throughputDelay	<- f throughputDelayText	(throughputDelay defaultDelay)
-	colors		<- makeColorsFromList <$> zipWithM (\a b -> f (colorText ++ [a]) b) ['0'..'7'] defaultColors
-	return Config{delays = Delay{..}, ..}
-	where
-	f :: Read b  => String -> b -> State [(String, String)] b
-	f key d = do
-		s <- get
-		let (e, s') = lookupDelete key s
-		put s'
-		return $ SM.fromMaybe d $ smread =<< e
-	defaultColors = TFNone "#000000" : map TFColor ["#d60503", "#25c200", "#eab93d", "#0021fe", "#04c9c9", "#e700d7"] ++ [TFNone "#000000"]
+    NP(masterServers)
+    NP(clanlistURL)
+    NP(tremulousPath)
+    NP(tremulousGppPath)
+    NP(unvanquishedPath)
+    NP(refreshMode)
+    NP(autoClan)
+    NP(restoreGeometry)
+    NPF(autoRefreshDelay, (*1000000))
+    NP(filterBrowser)
+    NP(filterPlayers)
+    NP(showEmpty)
+    NP(browserSortColumn)
+    NP(playersSortColumn)
+    NP(clanlistSortColumn)
+    NPF(browserOrder , conv)
+    NPF(playersOrder , conv)
+    NPF(clanlistOrder, conv)
+    NP_NODEF(packetTimeout) (packetTimeout defaultDelay)
+    NP_NODEF(packetDuplication) (packetDuplication defaultDelay)
+    NP_NODEF(throughputDelay) (throughputDelay defaultDelay)
+    colors <- makeColorsFromList <$> zipWithM
+        (\a b -> getKV ("color" ++ [a]) id b)
+        ['0'..'7']
+        (elems (colors defaultConfig))
+    return Config{delays = Delay{..}, ..}
+    where
+    conv :: SortingOrderPretty -> SortType
+    conv = toEnum . fromEnum
+    getKV :: Read b  => String -> (b -> c) -> c -> State [(String, String)] c
+    getKV key f def = do
+        s <- get
+        let (e, s') = lookupDelete key s
+        put s'
+        return $ SM.maybe def f $ smread =<< e
 
+
 smread :: (Read a) => String -> SM.Maybe a
 smread x = case reads x of
-	[(a, _)]	-> SM.Just a
-	_		-> SM.Nothing
+    [(a, _)]    -> SM.Just a
+    _       -> SM.Nothing
 
+makeColorsFromList :: [e] -> Array Int e
+makeColorsFromList = listArray (0,7)
+
 parse :: String -> Config
 parse = newParse . map (breakDrop isSpace) . lines
 
-mastersText, clanText, t11Text, t12Text, refreshModeText, autoClanText, geometryText, autoDelayText
-	, browserfilterText, playerfilterText, showEmptyText, browserSortText, playerSortText
-	, browserOrderText, playerOrderText, packetTimeoutText, clanlistSortText, clanlistOrderText
-	, packetDuplicationText, throughputDelayText, colorText :: String
-mastersText		= "masters"
-clanText		= "clanlistUrl"
-t11Text			= "tremulous1.1"
-t12Text			= "tremulousGPP"
-refreshModeText		= "refreshMode"
-autoClanText		= "autoClan"
-geometryText		= "saveGeometry"
-autoDelayText		= "autoDelay"
-browserfilterText	= "browserFilter"
-playerfilterText	= "playersFilter"
-showEmptyText		= "showEmpty"
-browserSortText		= "browserSortColumn"
-playerSortText		= "playerSortColumn"
-clanlistSortText	= "clanlistSortColumn"
-browserOrderText	= "browserSortingOrder"
-playerOrderText		= "playerSortingOrder"
-clanlistOrderText	= "clanlistSortingOrder"
-packetTimeoutText	= "packetTimeout"
-packetDuplicationText	= "packetDuplication"
-throughputDelayText	= "throughputDelay"
-colorText		= "color"
 
-makeColorsFromList :: [e] -> Array Int e
-makeColorsFromList = listArray (0,7)
-
 configToFile :: Window -> Config -> IO ()
 configToFile win config = do
-	file <- inConfDir "config"
-	handle err $ do
-	writeFile file (newSave config)
-	where
-	err (e::IOError) = gtkWarn win $ "Unable to save settings:\n" ++ show e
-
+    file <- inConfDir "config"
+    handle err $ writeFile file (newSave config)
+    where
+    err (e::IOError) = gtkWarn win $ "Unable to save settings:\n" ++ show e
 
 configFromFile :: IO Config
-configFromFile = handle err $ do
-	file	<- inConfDir "config"
-	cont	<- readFile file
-	return $ parse cont
-	where
-	err (_::IOError) = return $ parse ""
+configFromFile = catch
+    (parse <$> (readFile =<< inConfDir "config"))
+    (\(_::IOError) -> return defaultConfig)
diff --git a/src/Constants.hs b/src/Constants.hs
--- a/src/Constants.hs
+++ b/src/Constants.hs
@@ -8,6 +8,7 @@
 import System.Process
 import Control.Concurrent
 import Control.Exception
+import Control.Monad
 
 #ifdef CABAL_PATH
 import Paths_apelsin hiding (getDataDir)
@@ -39,19 +40,16 @@
 #endif
 
 
-defaultTremulousPath, defaultTremulousGPPPath:: FilePath
 trace :: String -> IO ()
 defaultBrowser :: String -> IO CreateProcess
+
 #if defined(mingw32_HOST_OS) || defined(__MINGW32__)
-defaultTremulousPath	= "C:\\Program Files\\Tremulous\\tremulous.exe"
-defaultTremulousGPPPath	= "C:\\Program Files\\Tremulous\\tremulous-gpp.exe"
 trace _			= return ()
 defaultBrowser x	= do
 	ddir <- getDataDir
 	return (proc "wscript" [ddir </> "open.js", x])
+
 #else
-defaultTremulousPath	= "tremulous"
-defaultTremulousGPPPath	= "tremulous-gpp"
 trace x			= hPutStrLn stderr x >> hFlush stderr
 
 #if defined(__APPLE__) || defined(__MACH__)
@@ -68,7 +66,7 @@
 	(_,_,_,hdl) <- createProcess p {close_fds = True}
 	-- The following hack is needed to avoid ghost processes because of:
 	-- http://hackage.haskell.org/trac/ghc/ticket/2123
-	forkIO $ waitForProcess hdl >> return ()
+	forkIO $ void $ waitForProcess hdl
 	return ()
 
 spacing, spacingHalf, spacingBig, spacingHuge :: Integral i => i
diff --git a/src/FindPlayers.hs b/src/FindPlayers.hs
--- a/src/FindPlayers.hs
+++ b/src/FindPlayers.hs
@@ -31,7 +31,7 @@
 		s <- readIORef current
 		return $ smartFilter s
 				[ cleanedCase item
-				, proto2string protocol
+				, protoToAbbr protocol
 				, SM.maybe "" cleanedCase gamemod
 				]
 
@@ -57,23 +57,23 @@
 
 	addColumnFS gen "_Name" True (Just (comparing fst))
 		(rememberColumn bundle 0)
-		cellRendererTextNew
+		fastCellTextRenderer
 		[cellTextEllipsize := EllipsizeEnd]
 		(\rend -> cellSetMarkup rend . pangoPrettyBS colors . fst)
 
 	addColumnFS gen "_Server" True (Just (comparing (hostname . snd)))
 		(rememberColumn bundle 1)
-		cellRendererTextNew
+		fastCellTextRenderer
 		[cellTextEllipsize := EllipsizeEnd]
 		(\rend -> cellSetMarkup rend . pangoPrettyBS colors . hostname . snd)
 
-	treeSortableSetSortColumnId sorted playersSort playersOrder
+	treeSortableSetSortColumnId sorted playersSortColumn playersOrder
 
 	on view cursorChanged $ do
 		(path, _) <- treeViewGetCursor view
 		setCurrent False . snd =<< getElementPath gen path
 
-	on view rowActivated $ \path _ -> do
+	on view rowActivated $ \path _ ->
 		setCurrent True . snd =<< getElementPath gen path
 
 	return gen
@@ -96,6 +96,6 @@
 rememberColumn Bundle{..} n col = do
 	order <- treeViewColumnGetSortOrder col
 	current <- takeMVar mconfig
-	let new = current {playersSort = n, playersOrder = order}
+	let new = current {playersSortColumn = n, playersOrder = order}
 	putMVar mconfig new
 	configToFile parent new
diff --git a/src/GtkUtils.hs b/src/GtkUtils.hs
--- a/src/GtkUtils.hs
+++ b/src/GtkUtils.hs
@@ -55,6 +55,7 @@
 			=> !(store a)
 			-> !TreeView
 			-> GenSimple store a
+
 data GenFilterSort store a where
 	GenFilterSort	:: ( TreeModelClass (store a), TypedTreeModelClass store
 			   , TreeModelClass filter, TreeModelFilterClass filter
@@ -82,14 +83,14 @@
 	treeSortableSetDefaultSortFunc sorted Nothing
 	return (GenFilterSort store filtered sorted view)
 
+
 addColumn :: GenSimple a e -> String -> Bool -> [AttrOp CellRendererText] -> (CellRendererText -> e -> IO ()) -> IO Int
 addColumn gen@(GenSimple store view) title expand rendOpts f = do
 	col <- treeViewColumnNew
 	set col	[ treeViewColumnTitle := title
 		, treeViewColumnExpand := expand ]
-	rend <- cellRendererTextNew
+	rend <- fastCellTextRenderer
 	set rend rendOpts
-	set rend [cellTextEllipsize := EllipsizeEnd]
 	cellLayoutPackStart col rend True
 	cellLayoutSetAttributeFunc col rend store $ \iter -> do
 		item <- getElementIter gen iter
@@ -127,6 +128,11 @@
 			g <$> treeModelGetRow store rit1 <*> treeModelGetRow store rit2
 
 
+fastCellTextRenderer :: IO CellRendererText
+fastCellTextRenderer = do
+	rend <- cellRendererTextNew
+	cellRendererTextSetFixedHeightFromFont rend 1
+	return rend
 
 getIterUnsafe :: TreeModelClass self => self -> TreePath -> IO TreeIter
 getIterUnsafe model path =
diff --git a/src/IndividualServerSettings.hs b/src/IndividualServerSettings.hs
--- a/src/IndividualServerSettings.hs
+++ b/src/IndividualServerSettings.hs
@@ -48,7 +48,7 @@
 toFile settings = tryIO $ do
 	fx <- configFile
 	writeFile fx $ unlines $ map f $ M.toList settings
-	where f ((SockAddrInet (PortNum port) ip), ServerArg a b c d) = intercalate "\t"
+	where f (SockAddrInet (PortNum port) ip, ServerArg a b c d) = intercalate "\t"
 		[ intToHex 8 (ntohl ip)
 		, intToHex 4 (ntohs port)
 		, a, b, c
diff --git a/src/InfoBox.hs b/src/InfoBox.hs
--- a/src/InfoBox.hs
+++ b/src/InfoBox.hs
@@ -6,10 +6,10 @@
 newInfobox what = do
 	lst <- mapM (labelNew . Just)
 		["Showing", "0", " out of", "0", ' ' : what]
-		
+
 	let (_:a:_:b:_) = lst
 	mapM_ (\x -> set x [ labelWidthChars := 4 ] >> miscSetAlignment x 1 0) [a,b]
-	
+
 	bar <- mkStatusBar lst
 	return (bar, a, b)
 
@@ -21,7 +21,7 @@
 	let (_:a:_:b:_:c:_) = lst
 	mapM_ (\x -> set x [ labelWidthChars := 4 ] >> miscSetAlignment x 1 0) [a,b,c]
 	set c [ labelWidthChars := 3 ]
-	
+
 	bar <- mkStatusBar lst
 	return (bar, a, b, c)
 
@@ -34,5 +34,3 @@
 	boxPackStart vb sep PackNatural 0
 	boxPackStart vb box PackNatural 0
 	return vb
-	
-	
diff --git a/src/Monad2.hs b/src/Monad2.hs
--- a/src/Monad2.hs
+++ b/src/Monad2.hs
@@ -14,10 +14,10 @@
 	Just a	-> f a
 
 whenM :: Monad m => m Bool -> m () -> m ()
-whenM c m = c >>= \t -> if t then m else return ()
+whenM c m = c >>= \t -> when t m
 
 unlessM :: Monad m => m Bool -> m () -> m ()
-unlessM c m = c >>= \t -> if not t then m else return ()
+unlessM c m = c >>= \t -> when (not t) m
 
 getDNS :: String -> String -> IO (Maybe SockAddr)
 getDNS host port = handle (\(_ :: IOException) -> return Nothing) $
diff --git a/src/NumberSerializer.hs b/src/NumberSerializer.hs
--- a/src/NumberSerializer.hs
+++ b/src/NumberSerializer.hs
@@ -2,6 +2,7 @@
 import Data.Bits
 import Network.Tremulous.SocketExtensions
 import Network.Socket
+import Data.Foldable
 
 intToHex :: (Integral i, Bits i) => Int -> i -> String
 intToHex = go [] where
@@ -12,9 +13,8 @@
 	conv = toEnum . fromIntegral
 
 hexToInt :: (Integral i, Bits i) => String -> i
-hexToInt = go 0 where
-	go b []     = b
-	go b (x:xs) = go ((b `shiftL` 4) .|. toInt x) xs
+hexToInt = foldl' (\acc x -> (acc `shiftL` 4) .|. toInt x) 0
+	where
 	toInt c | c' <= 0x39 = c' - 0x30
 	        | otherwise  = c' - (0x61-0xa)
 	        where c' = conv c
@@ -22,4 +22,6 @@
 
 
 stringToSockAddr :: String -> String -> SockAddr
-stringToSockAddr ip port = SockAddrInet (PortNum (htons (hexToInt port))) (htonl (hexToInt ip))
+stringToSockAddr ip port = SockAddrInet
+	(PortNum (htons (hexToInt port)))
+	(htonl (hexToInt ip))
diff --git a/src/OnlineClans.hs b/src/OnlineClans.hs
--- a/src/OnlineClans.hs
+++ b/src/OnlineClans.hs
@@ -67,7 +67,7 @@
 type OnlineView = Forest (Either Clan (TI, P.GameServer))
 
 associatePlayerToClans :: PlayerList -> [Clan] -> [(Clan, PlayerList)]
-associatePlayerToClans players clans = map f clans
+associatePlayerToClans players = map f
 	where
 	f c@Clan{tagexpr} = (c, filter (cmp tagexpr) players)
 	cmp e = matchTagExpr e . fst
diff --git a/src/Preferences.hs b/src/Preferences.hs
--- a/src/Preferences.hs
+++ b/src/Preferences.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE CPP #-}
+-- This file is horribly coded :( A good example why the gtk code should be separate
 module Preferences (newPreferences) where
 import Graphics.UI.Gtk
 
@@ -31,7 +32,7 @@
 	-- Default filters
 	(  tbl
 	 , [filterBrowser, filterPlayers]
-	 , filterEmpty
+	 , showEmpty
 	 ) <- configTable
 		[ "_Browser:"
 		, "_Find players:"
@@ -39,38 +40,42 @@
 	filters <- framed "Default filters" tbl
 
 	-- Tremulous path
-	(pathstbl, [tremPath, tremGppPath]) <- pathTable parent ["_Tremulous 1.1:", "Tremulous _GPP:"]
-	paths <- framed "Tremulous path or command" pathstbl
+	path_table       <- paddedTableNew
+	tremulousPath    <- pathInsertTable parent path_table 0 "_Tremulous 1.1:"
+	tremulousGppPath <- pathInsertTable parent path_table 1 "Tremulous _GPP:"
+	unvanquishedPath <- pathInsertTable parent path_table 2 "_Unvanquished:"
+	paths            <- framed "Path or command" path_table
 
 	-- Startup
 	autoClan	<- checkButtonNewWithMnemonic "_Sync clan list"
-	autoGeometry	<- checkButtonNewWithMnemonic "Restore _window geometry from previous session"
+	restoreGeometry	<- checkButtonNewWithMnemonic "Restore _window geometry from previous session"
 	startupBox <- vBoxNew False 0
 	boxPackStartDefaults startupBox autoClan
-	boxPackStartDefaults startupBox autoGeometry
+	boxPackStartDefaults startupBox restoreGeometry
 	startup <- framed "On startup" startupBox
 
 	--Refresh mode
 	rb1 <- radioButtonNewWithMnemonic "_Once at startup"
-	rb2 <- radioButtonNewWithMnemonicFromWidget rb1 "_Periodically each"
+	rb2 <- radioButtonNewWithMnemonicFromWidget rb1 "_Periodically"
 	rb3 <- radioButtonNewWithMnemonicFromWidget rb1 "_Manually"
-	autoDelay <- spinButtonNewWithRange 0 3600 1
-	seconds <- labelNew (Just "s")
 
+	ar <- labelNewWithMnemonic "_Auto Refresh period:"
+	autoRefreshDelay <- spinButtonNewWithRange 0 3600 1
+	set ar [labelMnemonicWidget := autoRefreshDelay]
+	seconds <- labelNew (Just "s")
 	delaybox <- hBoxNew False spacing
-	boxPackStart delaybox autoDelay PackNatural 0
+	boxPackStart delaybox ar PackNatural 0
+	boxPackStart delaybox autoRefreshDelay PackNatural 0
 	boxPackStart delaybox seconds PackNatural 0
 
-	perbox <- hBoxNew False spacingBig
-	boxPackStart perbox rb2 PackNatural 0
-	boxPackStart perbox delaybox PackNatural 0
-
 	rbBox <- vBoxNew False 0
 	boxPackStartDefaults rbBox rb1
-	boxPackStartDefaults rbBox perbox
+	boxPackStartDefaults rbBox rb2
 	boxPackStartDefaults rbBox rb3
+	boxPackStartDefaults rbBox delaybox
 	refreshmode <- framed "Refresh all" rbBox
 
+
 	-- Colors
 	(colorTbl, colorList) <- numberedColors
 	colorWarning <- labelNew (Just "Note: Requires a restart to take effect")
@@ -108,12 +113,13 @@
 		let Delay{..} = C.delays c
 		set filterBrowser	[ entryText := C.filterBrowser c ]
 		set filterPlayers	[ entryText := C.filterPlayers c ]
-		set filterEmpty		[ toggleButtonActive := C.filterEmpty c]
-		set tremPath		[ entryText := C.tremPath c ]
-		set tremGppPath		[ entryText := C.tremGppPath c]
+		set showEmpty		[ toggleButtonActive := C.showEmpty c]
+		set tremulousPath	[ entryText := C.tremulousPath c ]
+		set tremulousGppPath	[ entryText := C.tremulousGppPath c]
+		set unvanquishedPath	[ entryText := C.unvanquishedPath c]
 		set autoClan		[ toggleButtonActive := C.autoClan c]
-		set autoGeometry	[ toggleButtonActive := C.autoGeometry c]
-		set autoDelay		[ spinButtonValue := fromIntegral (C.autoDelay c `quot` 1000000) ]
+		set restoreGeometry	[ toggleButtonActive := C.restoreGeometry c]
+		set autoRefreshDelay	[ spinButtonValue := fromIntegral (C.autoRefreshDelay c `quot` 1000000) ]
 		set packetTimeout'	[ spinButtonValue := fromIntegral (packetTimeout `quot` 1000) ]
 		set packetDuplication'	[ spinButtonValue := fromIntegral packetDuplication ]
 		set throughputDelay'	[ spinButtonValue := fromIntegral (throughputDelay `quot` 1000) ]
@@ -122,27 +128,23 @@
 		set rb3			[ toggleButtonActive := C.refreshMode c == C.Manual ]
 
 		zipWithM_ f colorList (elems (C.colors c))
-		where	f (a, b) (TFColor c) = do
-				colorButtonSetColor a (hexToColor c)
-				toggleButtonSetActive b True
-			f (a ,b) (TFNone c) = do
-				colorButtonSetColor a (hexToColor c)
-				toggleButtonSetActive b False
-				-- Apparently this is needed too
+		where	f (a, b) (TremFmt active color) = do
+				colorButtonSetColor a (hexToColor color)
+				toggleButtonSetActive b active
 				toggleButtonToggled b
 
 	updateF
 
 	_CONNECT(filterBrowser, editableChanged, entryText, C.filterBrowser)
-	_CONNECT(filterEmpty, toggled, toggleButtonActive, C.filterEmpty)
+	_CONNECT(showEmpty, toggled, toggleButtonActive, C.showEmpty)
 	_CONNECT(filterPlayers, editableChanged, entryText, C.filterPlayers)
 
-	_CONNECT(tremPath, editableChanged, entryText, C.tremPath)
-	_CONNECT(tremGppPath, editableChanged, entryText, C.tremGppPath)
+	_CONNECT(tremulousPath, editableChanged, entryText, C.tremulousPath)
+	_CONNECT(tremulousGppPath, editableChanged, entryText, C.tremulousGppPath)
+	_CONNECT(unvanquishedPath, editableChanged, entryText, C.unvanquishedPath)
 
-	--_CONNECT(autoMaster, toggled, toggleButtonActive, C.autoMaster)
 	_CONNECT(autoClan, toggled, toggleButtonActive, C.autoClan)
-	_CONNECT(autoGeometry, toggled, toggleButtonActive, C.autoGeometry)
+	_CONNECT(restoreGeometry, toggled, toggleButtonActive, C.restoreGeometry)
 
 
 	let radiofunc value = update (\x -> x { C.refreshMode = value})
@@ -154,9 +156,9 @@
 	on rb3 toggled $ do	b <- toggleButtonGetActive rb3
 				when b (radiofunc C.Manual)
 
-	onValueSpinned autoDelay $ do
-		value <- (*1000000) <$> spinButtonGetValueAsInt autoDelay
-		update (\x -> x { C.autoDelay = fromIntegral value})
+	onValueSpinned autoRefreshDelay $ do
+		value <- (*1000000) <$> spinButtonGetValueAsInt autoRefreshDelay
+		update (\x -> x { C.autoRefreshDelay = fromIntegral value})
 
 	onValueSpinned packetTimeout' $ do
 		packetTimeout <- (*1000) <$> spinButtonGetValueAsInt packetTimeout'
@@ -171,13 +173,12 @@
 		update (\x -> let delays = C.delays x in x {C.delays = delays {throughputDelay}})
 
 	let updateColors = do
-		rawcolors <- forM colorList $ \(colb, cb) -> do
-			bool <- get cb toggleButtonActive
-			(if bool then TFColor else TFNone)
-				 . colorToHex <$> colorButtonGetColor colb
+		rawcolors <- forM colorList $ \(colb, cb) ->
+			TremFmt <$> get cb toggleButtonActive
+				<*> (colorToHex <$> colorButtonGetColor colb)
 		update $ \x -> x {C.colors = C.makeColorsFromList rawcolors}
 
-	forM colorList $ \(colb, cb) -> do
+	forM_ colorList $ \(colb, cb) -> do
 		on cb toggled updateColors
 		afterColorSet colb updateColors
 
@@ -206,20 +207,15 @@
 	rt <- zipWithM easyAttach [0..] ys
 	return (tbl, rt, empty)
 
-pathTable :: Window -> [String] -> IO (Table, [Entry])
-pathTable parent ys = do
-	tbl <- paddedTableNew
-	let easyAttach pos lbl  = do
-		a <- labelNewWithMnemonic lbl
-		(box, ent) <- pathSelectionEntryNew parent
-		set a [ labelMnemonicWidget := ent ]
-		miscSetAlignment a 0 0.5
-		tableAttach tbl a 0 1 pos (pos+1) [Fill] [] 0 0
-		tableAttach tbl box 1 2 pos (pos+1) [Expand, Fill] [] 0 0
-		return ent
-
-	rt	<- zipWithM easyAttach [0..] ys
-	return (tbl, rt)
+pathInsertTable :: Window -> Table -> Int -> String -> IO Entry
+pathInsertTable parent tbl pos lbl = do
+	a <- labelNewWithMnemonic lbl
+	(box, ent) <- pathSelectionEntryNew parent
+	set a [ labelMnemonicWidget := ent ]
+	miscSetAlignment a 0 0.5
+	tableAttach tbl a 0 1 pos (pos+1) [Fill] [] 0 0
+	tableAttach tbl box 1 2 pos (pos+1) [Expand, Fill] [] 0 0
+	return ent
 
 mkInternals :: IO (Table, [SpinButton])
 mkInternals = do
@@ -239,7 +235,7 @@
 
 	let mkTable = zipWithM easyAttach [0..]
 	rt <- mkTable	[ ("Respo_nse Timeout:", "ms", "How long Apelsin should wait before sending a new request to a server possibly not responding")
-			, ("Maximum packet _duplication:", "times", "Maximum number of extra requests to send beoynd the initial one if a server does not respond" )
+			, ("Maximum extra _requests:", "times", "Maximum number of extra requests to send beoynd the initial one if a server does not respond" )
 			, ("Throughput _limit:", "ms", "Should be set as low as possible as long as pings from \"Refresh all servers\" remains the same as \"Refresh current\"") ]
 	return (tbl, rt)
 
diff --git a/src/ServerBrowser.hs b/src/ServerBrowser.hs
--- a/src/ServerBrowser.hs
+++ b/src/ServerBrowser.hs
@@ -25,45 +25,46 @@
 	addColumnFS gen "_Game" False
 		(Just (comparing protocol `mappend` comparing gamemod `mappend` comparing gameping))
 		(rememberColumn bundle 0)
-		cellRendererTextNew
+		fastCellTextRenderer
 		[]
 		(\rend -> cellSetText rend . showGame)
 
 	addColumnFS gen "_Name" True
 		(Just (comparing hostname `mappend` comparing gameping))
 		(rememberColumn bundle 1)
-		cellRendererTextNew
+		fastCellTextRenderer
 		[cellTextEllipsize := EllipsizeEnd]
 		(\rend -> cellSetMarkup rend . pangoPrettyBS colors . hostname)
 
 	addColumnFS gen "_Map" False
 		(Just (comparing mapname `mappend` comparing gameping))
 		(rememberColumn bundle 2)
-		cellRendererTextNew []
+		fastCellTextRenderer
+		[]
 		(\rend -> cellSetText rend . SM.maybe "" (B.take 16 . original) . mapname)
 
 	addColumnFS gen "P_ing" False
 		(Just (comparing gameping `mappend` comparing hostname))
 		(rememberColumn bundle 3)
-		cellRendererTextNew
+		fastCellTextRenderer
 		[cellXAlign := 1]
 		(\rend x -> set rend [cellText := show $ gameping x])
 
 	addColumnFS gen "_Players" False
 		(Just (comparing nplayers `mappend` flip (comparing gameping)))
 		(rememberColumn bundle 4)
-		cellRendererTextNew
+		fastCellTextRenderer
 		[cellXAlign := 1]
 		(\rend x -> set rend [cellText := showPlayers x])
 
 
-	treeSortableSetSortColumnId sorted browserSort browserOrder
+	treeSortableSetSortColumnId sorted browserSortColumn browserOrder
 
 	(infobox, statNow, statTot, statRequested) <- newInfoboxBrowser
 
 	(filterbar, current) <- newFilterBar parent filtered statNow filterBrowser
 	empty <- checkButtonNewWithMnemonic "_empty"
-	set empty [ toggleButtonActive := filterEmpty ]
+	set empty [ toggleButtonActive := showEmpty ]
 	boxPackStart filterbar empty PackNatural spacingHalf
 	on empty toggled $ do
 		treeModelFilterRefilter filtered
@@ -73,15 +74,14 @@
 	treeModelFilterSetVisibleFunc filtered $ \iter -> do
 		GameServer{..}	<- treeModelGetRow raw iter
 		s		<- readIORef current
-		showEmpty	<- toggleButtonGetActive empty
-		return $ (showEmpty || not (null players)) &&
-			(smartFilter s
-				[ cleanedCase hostname
-				, SM.maybe "" cleanedCase mapname
-				, SM.maybe "" cleanedCase version
-				, proto2string protocol
-				, SM.maybe "" cleanedCase gamemod
-				])
+		showEmpty_	<- toggleButtonGetActive empty
+		return $ (showEmpty_ || nplayers > 0) &&
+			smartFilter s	[ cleanedCase hostname
+							, SM.maybe "" cleanedCase mapname
+							, SM.maybe "" cleanedCase version
+							, protoToAbbr protocol
+							, SM.maybe "" cleanedCase gamemod
+							]
 
 	on view cursorChanged $ do
 		(path, _) <- treeViewGetCursor view
@@ -109,7 +109,7 @@
 
 	return (box, updateF)
 	where
-	showGame GameServer{..} = B.concat (proto2string protocol : SM.maybe [] ((\x -> ["-",x]) . original) gamemod)
+	showGame GameServer{..} = B.concat (protoToAbbr protocol : SM.maybe [] ((\x -> ["-",x]) . original) gamemod)
 	showPlayers GameServer{..} = printf "%d / %2d" nplayers slots
 
 browserUpdateOne :: BrowserStore -> GameServer -> IO ()
@@ -124,6 +124,6 @@
 rememberColumn Bundle{..} n col = do
 	order <- treeViewColumnGetSortOrder col
 	current <- takeMVar mconfig
-	let new = current {browserSort = n, browserOrder = order}
+	let new = current {browserSortColumn = n, browserOrder = order}
 	putMVar mconfig new
 	configToFile parent new
diff --git a/src/ServerInfo.hs b/src/ServerInfo.hs
--- a/src/ServerInfo.hs
+++ b/src/ServerInfo.hs
@@ -112,7 +112,7 @@
 
 		if natural * 2 > h then
 			let half = max 0 (h`quot`2) in setS half half
-		else if (max sReq natural) + pReq + spacing <= h then
+		else if max sReq natural + pReq + spacing <= h then
 			setS (-1) (max sReq natural)
 		else do
 			let ratio	= fromIntegral pReq / (fromIntegral sReq + fromIntegral pReq) :: Double
@@ -156,12 +156,13 @@
 		pid <- maybeIO $ runTremulous config gs (getSettings (address gs) ss)
 		case pid of
 			Nothing -> do
-				gtkError parent $ "Unable to run \"" ++ path ++ "\".\nHave you set your path correctly in Preferences?"
+				let msg = case protocolToPath config (protocol gs) of
+					Just path -> "Unable to run \"" ++ path ++ "\".\nHave you set your path correctly in Preferences?"
+					Nothing   -> "Unknown game (protocol: " ++ show (protocol gs) ++ ")"
+				gtkError parent msg
 				set join [ widgetSensitive := True ]
 				takeMVar running
-				where path = case protocol gs of
-						70 -> tremGppPath config
-						_  -> tremPath config
+
 			Just a -> do
 				autoSignal mauto AutoPause
 				forkIO $ do
@@ -171,8 +172,6 @@
 					autoSignal mauto AutoResume
 				return ()
 
-
-
 	let updateSettings joining = do
 		gs@GameServer{..}	<- readMVar current
 		ss			<- readMVar msettings
@@ -195,24 +194,24 @@
 
 
 	on join buttonActivated $ readWithMVar current launchWithSettings
-	on st buttonActivated (updateSettings False >> return ())
+	on st buttonActivated $ void $ updateSettings False
 
 
 	let setF boolJoin gs@GameServer{..} = do
 		labelSetMarkup hostnamex $ showHostname colors hostname
 		zipWithM_ labelSetMarkup info
 			[ show address
-			, (proto2string protocol ++ (case gamemod of
+			, protoToFull protocol ++ (case gamemod of
 					SM.Nothing	-> ""
-					SM.Just z	-> " (" ++ (unpack . original) z ++ ")"))
+					SM.Just z	-> " (" ++ (unpack . original) z ++ ")")
 			, maybeS mapname
 			, maybeQ timelimit ++ " / " ++ maybeQ suddendeath
-			, show slots ++ " (+" ++ maybeQ privslots ++ ")"
+			, show slots ++ " (+" ++ show privslots ++ ")"
 			, show gameping ++ " / " ++ meanPing players
 			, maybeS version
 			]
 		labelSetText versionLabel (maybeS version)
-		labelSetText bools $	unwords	[ if unlagged then "unlagged" else ""
+		labelSetText bools $ unwords [ if unlagged then "unlagged" else ""
 						, if protected then "password" else "" ]
 
 		listStoreClear amodel
@@ -292,15 +291,29 @@
 	maybeS			= SM.maybe "" (unpack . original)
 	meanPing		= show . intmean . filter validping . map ping
 
+
+protocolToPath :: Config -> Int -> Maybe FilePath
+protocolToPath c proto = case proto of
+	69 -> Just (tremulousPath c)
+	70 -> Just (tremulousGppPath c)
+	86 -> Just (unvanquishedPath c)
+	_  -> Nothing
+
+
 runTremulous :: Config -> GameServer -> ServerArg-> IO (Maybe ProcessHandle)
-runTremulous Config{..} GameServer{..} ServerArg{..} = do
-	(_,_,_,p) <- createProcess (proc com args) {cwd = ldir, close_fds = True}
-	maybe (Just p) (const Nothing) <$> getProcessExitCode p
-	where
-	com = case protocol of
-		70 -> tremGppPath
-		_  -> tremPath
+runTremulous config GameServer{..} ServerArg{..} =
+	case protocolToPath config protocol of
+		Just com -> do
+			(_,_,_,p) <- createProcess (proc com args) {cwd = ldir, close_fds = True}
+			maybe (Just p) (const Nothing) <$> getProcessExitCode p
+			where
+			ldir = case takeDirectory com of
+				"" -> Nothing
+				x  -> Just x
 
+		Nothing ->
+			return Nothing
+	where
 	args = concatMap (uncurry arg)
 			[ ("connect", show address)
 			, ("password", serverPass)
@@ -308,10 +321,8 @@
 			, ("name", serverName)
 			]
 
-	ldir = case takeDirectory com of
-		"" -> Nothing
-		x  -> Just x
 
+
 arg :: String -> String -> [String]
 arg _ "" = []
 arg a s  = ['+':a, s]
@@ -324,9 +335,9 @@
 	addColumn gen teamName True [cellTextEllipsize := EllipsizeEnd] $ \rend ->
 		cellSetMarkup rend . pangoPrettyBS colors . name
 	when showScore $ do
-		addColumn gen "Score" False [cellXAlign := 1] $ \rend item -> do
+		addColumn gen "Score" False [cellXAlign := 1] $ \rend item ->
 			set rend  [cellText := show $ kills item]
 		return ()
 	addColumn gen "Ping" False [cellXAlign := 1] $ \rend item ->
-			set rend [ cellText := show $ ping item]
+			set rend [cellText := show $ ping item]
 	return gen
diff --git a/src/SettingsDialog.hs b/src/SettingsDialog.hs
--- a/src/SettingsDialog.hs
+++ b/src/SettingsDialog.hs
@@ -43,7 +43,7 @@
 		set b	[ entryActivatesDefault := True
 			, entryText		:= def
 			, entryWidthChars	:= 30 ]
-		when (pos == 1 && requirepw) $ do
+		when (pos == 1 && requirepw) $
 			labelSetAttributes a [AttrWeight 0 (-1) WeightBold]
 
 		set a	[ labelMnemonicWidget	:= b
diff --git a/src/System/Environment/XDG/BaseDir.hs b/src/System/Environment/XDG/BaseDir.hs
deleted file mode 100644
--- a/src/System/Environment/XDG/BaseDir.hs
+++ /dev/null
@@ -1,103 +0,0 @@
-{-# LANGUAGE CPP #-}
-
-module System.Environment.XDG.BaseDir
-    ( getUserDataDir
-    , getUserDataFile
-    , getUserConfigDir
-    , getUserConfigFile
-    , getUserCacheDir
-    , getUserCacheFile
-    , getSystemDataDirs
-    , getSystemDataFiles
-    , getSystemConfigDirs
-    , getSystemConfigFiles
-    , getAllDataDirs
-    , getAllDataFiles
-    , getAllConfigDirs
-    , getAllConfigFiles
-    ) where
-
-import System.FilePath    ( (</>), splitSearchPath )
-import System.Environment
-import System.Directory   ( getHomeDirectory )
-import Control.Monad      ( liftM2 )
-
-getDefault :: String -> IO FilePath
-#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
-
-getDefault "XDG_DATA_HOME"   = getEnv "AppData"
-getDefault "XDG_CONFIG_HOME" = userRelative $ "Local Settings"
-getDefault "XDG_CACHE_HOME"  = userRelative $ "Local Settings" </> "Cache"
-getDefault "XDG_DATA_DIRS"   = getEnv "ProgramFiles"
-getDefault "XDG_CONFIG_DIRS" = getEnv "ProgramFiles"
-getDefault _                 = return ""
-
-#else
-
-getDefault "XDG_DATA_HOME"   = userRelative $ ".local" </> "share"
-getDefault "XDG_CONFIG_HOME" = userRelative $ ".config"
-getDefault "XDG_CACHE_HOME"  = userRelative $ ".cache"
-getDefault "XDG_DATA_DIRS"   = return $ "/usr/local/share:/usr/share"
-getDefault "XDG_CONFIG_DIRS" = return $ "/etc/xdg"
-getDefault _                 = return $ ""
-
-#endif
-
--- | Get the directory for user-specific data files.
-getUserDataDir      :: String -> IO FilePath
-getUserDataDir      = singleDir "XDG_DATA_HOME"
--- | Get the directory for user-specific configuration files.
-getUserConfigDir    :: String -> IO FilePath
-getUserConfigDir    = singleDir "XDG_CONFIG_HOME"
--- | Get the directory for user-specific cache files.
-getUserCacheDir     :: String -> IO FilePath
-getUserCacheDir     = singleDir "XDG_CACHE_HOME"
--- | Get a list of the system-wide data directories.
-getSystemDataDirs   :: String -> IO [FilePath]
-getSystemDataDirs   = multiDirs "XDG_DATA_DIRS"
--- | Get a list of the system-wide configuration directories.
-getSystemConfigDirs :: String -> IO [FilePath]
-getSystemConfigDirs = multiDirs "XDG_CONFIG_DIRS"
--- | Get a list of all data directories.
-getAllDataDirs      :: String -> IO [FilePath]
-getAllDataDirs a    = liftM2 (:) (getUserDataDir a) (getSystemDataDirs a)
--- | Get a list of all configuration directories.
-getAllConfigDirs    :: String -> IO [FilePath]
-getAllConfigDirs a  = liftM2 (:) (getUserConfigDir a) (getSystemConfigDirs a)
--- | Get the path to a specific user data file.
-getUserDataFile          :: String -> String -> IO FilePath
-getUserDataFile a f      = fmap (</> f) $ getUserDataDir a
--- | Get the path to a specific user configuration file.
-getUserConfigFile        :: String -> String -> IO FilePath
-getUserConfigFile a f    = fmap (</> f) $ getUserConfigDir a
--- | Get the path to a specific user cache file.
-getUserCacheFile         :: String -> String -> IO FilePath
-getUserCacheFile a f     = fmap (</> f) $ getUserCacheDir a
--- | Get a list of all paths for a specific system data file.
-getSystemDataFiles       :: String -> String -> IO [FilePath]
-getSystemDataFiles a f   = fmap (map (</> f)) $ getSystemDataDirs a
--- | Get a list of all paths for a specific system configuration file.
-getSystemConfigFiles     :: String -> String -> IO [FilePath]
-getSystemConfigFiles a f = fmap (map (</> f)) $ getSystemConfigDirs a
--- | Get a list of all paths for a specific data file.
-getAllDataFiles          :: String -> String -> IO [FilePath]
-getAllDataFiles a f      = fmap (map (</> f)) $ getAllDataDirs a
--- | Get a list of all paths for a specific configuration file.
-getAllConfigFiles        :: String -> String -> IO [FilePath]
-getAllConfigFiles a f    = fmap (map (</> f)) $ getAllConfigDirs a
-
-singleDir :: String -> String -> IO FilePath
-singleDir key app = envLookup key >>= return . (</> app)
-
-multiDirs :: String -> String -> IO [FilePath]
-multiDirs key app = envLookup key >>= return . map (</> app) . splitSearchPath
-
-envLookup :: String -> IO String
-envLookup key = do env <- getEnvironment
-                   case lookup key env of
-                        Just val -> return val
-                        Nothing  -> getDefault key
-
-userRelative :: FilePath -> IO FilePath
-userRelative p = getHomeDirectory >>= return . (</> p)
-
diff --git a/src/Toolbar.hs b/src/Toolbar.hs
--- a/src/Toolbar.hs
+++ b/src/Toolbar.hs
@@ -21,6 +21,7 @@
 import ClanFetcher
 import AutoRefresh
 
+
 newToolbar :: Bundle -> [ClanHook] -> [PolledHook] -> [ClanPolledHook] -> IO HBox
 newToolbar bundle@Bundle{..} clanHook polledHook bothHook = do
 	c		<- readMVar mconfig
@@ -68,9 +69,10 @@
 			[]	| k == "f5" -> liftIO doRefresh		>> return True
 			[]	| k == "f6" -> liftIO doSync		>> return True
 			[]	| k == "f7" -> liftIO (newAbout parent)	>> return True
+			[]	| k == "f8" -> liftIO (toggleButton auto)	>> return True
 			_ -> return False
 
-	case (refreshMode c) of
+	case refreshMode c of
 		Startup	-> doRefresh
 		Auto	-> autoSignal mauto AutoStart
 		Manual	-> return ()
@@ -78,6 +80,9 @@
 
 	return pbrbox
 
+toggleButton :: ToggleButton -> IO ()
+toggleButton b = toggleButtonSetActive b . not =<< toggleButtonGetActive b
+
 -- The reason a hbox is used is so the icons always gets displayed regardless of the gtk setting
 mkToolButton :: String -> StockId -> String -> IO Button
 mkToolButton text icon tip = do
@@ -101,7 +106,7 @@
 	containerAdd button img
 	set button	[ buttonRelief		:= ReliefNone
 			, buttonFocusOnClick	:= False
-			, widgetTooltipText	:= Just "Refresh all servers periodically" ]
+			, widgetTooltipText	:= Just "Refresh all servers periodically (F8)" ]
 	return button
 
 mLock :: WidgetClass w => w -> (IO () -> IO ()) -> IO (IO ())
@@ -119,9 +124,9 @@
 
 newClanSync :: Bundle -> [ClanHook] -> [ClanPolledHook] -> IO () -> IO ()
 newClanSync Bundle{..} clanHook bothHook unlock = do
-	Config {clanSyncURL} <- readMVar mconfig
+	Config {clanlistURL} <- readMVar mconfig
 	forkIO $ do
-		new <- getClanList clanSyncURL
+		new <- getClanList clanlistURL
 		case new of
 			Nothing	-> postGUISync $ gtkError parent "Unable to download clanlist"
 			Just a	-> do
@@ -145,8 +150,8 @@
 	let serversGuess = if serversResponded == 0 then 110 else serversResponded
 	let tremTime = (packetDuplication + 1) * packetTimeout
 		+ serversGuess * throughputDelay + 200 * 1000
-
-	forkIO $ do
+	-- Unmask in case this is called from a masked state
+	forkIOWithUnmask $ \un -> un $ do
 		hosts <- catMaybes <$> mapM
 			(\(host, port, proto) -> fmap (`MasterServer` proto) <$> getDNS host (show port))
 			masterServers
diff --git a/src/TremFormatting.hs b/src/TremFormatting.hs
--- a/src/TremFormatting.hs
+++ b/src/TremFormatting.hs
@@ -1,11 +1,12 @@
 module TremFormatting where
 import Data.Array
 import Data.Char
+import Data.String
 import Network.Tremulous.NameInsensitive
 import qualified Data.ByteString.Char8 as B
 import Data.ByteString.Char8 (ByteString)
 
-data TremFmt = TFColor !String | TFNone !String
+data TremFmt = TremFmt {active :: !Bool, color :: !String}
 	deriving (Show, Read)
 
 type ColorArray = Array Int TremFmt
@@ -25,21 +26,35 @@
 pangoPretty arr = pangoColors arr . B.unpack . original
 
 pangoColors :: ColorArray -> String -> String
-pangoColors arr = f False where
+pangoColors arr = go False where
 	--Replace with colors
-	f n ('^':x:xs) | isAlphaNum x = case arr ! (a `rem` 8) of
-		TFColor color	-> close n ++ "<span color=\"" ++ color ++ "\">" ++ f True xs
-		TFNone	_	-> close n ++ f False xs
-		where a = ord x - ord '0'
-	--Escape pango
-	f n (x:xs) = case x of
-		'<' -> "&lt;" ++ f n xs
-		'>' -> "&gt;" ++ f n xs
-		'&' -> "&amp;" ++ f n xs
-		_   -> x : f n xs
+	go n ('^':x:xs) | isAlphaNum x = close n ++ middle ++ go active xs
+		where
+		TremFmt {..} = arr ! ((ord x - ord '0') `rem` 8)
+		middle	| active	= "<span color=\"" ++ color ++ "\">"
+				| otherwise = ""
 
-	f n []		= close n
+	-- Escape pango
+	go n (x:xs) = case x of
+		'<' -> "&lt;" ++ go n xs
+		'>' -> "&gt;" ++ go n xs
+		'&' -> "&amp;" ++ go n xs
+		_   -> x : go n xs
 
+	go n []		= close n
+
 	close n = if n then "</span>" else ""
 
+	-- Protocol version
+protoToAbbr, protoToFull :: IsString s => Int ->  s
+protoToAbbr x = case x of
+	69 -> "1.1"
+	70 -> "gpp"
+	86 -> "unv"
+	_  -> "?"
 
+protoToFull x = case x of
+	69 -> "Tremulous 1.1"
+	70 -> "Tremulous GPP"
+	86 -> "Unvanquished"
+	_  -> "<Unknown>"
