diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,11 +1,11 @@
 gtk-sni-tray
 ===============
 
-gtk-sni-tray provides a [StatusNotifiedHost](https://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/StatusNotifierHost/) widget written using the gtk+3 bindings for haskell provided by [gi-gtk](https://hackage.haskell.org/package/gi-gtk). It also provides a simple standalone executable, `gtk-sni-tray-standalone`, that is configured with command line arguments. This executable will run the aforementioned widget by itself in a strut window, on each monitor for each it is requested.
+gtk-sni-tray provides a [StatusNotifierHost](https://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/StatusNotifierHost/) widget written using the gtk+3 bindings for haskell provided by [gi-gtk](https://hackage.haskell.org/package/gi-gtk). It also provides a simple standalone executable, `gtk-sni-tray-standalone`, that is configured with command line arguments. This executable will run the aforementioned widget by itself in a strut window, on each monitor for each it is requested.
 
 taffybar
 ----------
-It is generally recommeneded that you use this widget with [taffybar](https://github.com/travitch/taffybar), which will allow you to combine it with other useful widgets, and will give more flexibility in configuration.
+It is generally recommeneded that you use this widget through [taffybar](https://github.com/travitch/taffybar) with [this module](https://github.com/travitch/taffybar/blob/master/src/System/Taffybar/SNITray.hs), which will allow you to combine it with other useful widgets, and will give more flexibility in configuration.
 
 StatusNotifierWatcher
 --------------------------
@@ -16,4 +16,9 @@
 ```
 
 when you start `gtk-sni-tray-standalone` it is probably because you have not started a StatusNotifierWatcher on your system. You can solve this problem by passing the `--watcher` flag to `gtk-sni-tray-standalone`, but this is not recommeneded, because many SNI processes do not monitor for new watcher processes, and so may not immediately register when this new watcher is started.
+
+Installation
+---------------
+
+Both [`stack`](https://www.haskell.org/cabal/download.html) and [`cabal`](https://www.haskell.org/cabal/download.html) can be used to install gtk-sni-tray.
 
diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -8,8 +8,9 @@
 import           Data.Ratio
 import           Data.Semigroup ((<>))
 import qualified Data.Text as T
-import qualified GI.Gtk as Gtk
+import           Data.Version (showVersion)
 import qualified GI.Gdk as Gdk
+import qualified GI.Gtk as Gtk
 import           Graphics.UI.GIGtkStrut
 import           Options.Applicative
 import qualified StatusNotifier.Host.Service as Host
@@ -18,6 +19,8 @@
 import           System.Posix.Process
 import           Text.Printf
 
+import           Paths_gtk_sni_tray (version)
+
 positionP :: Parser StrutPosition
 positionP = fromMaybe TopPos <$> optional
   (   flag' TopPos
@@ -77,7 +80,7 @@
   option auto
   (  long "monitor"
   <> short 'm'
-  <> help "Run on the selected monitor"
+  <> help "Display a tray bar on the given monitor"
   <> metavar "MONITOR"
   )
 
@@ -96,16 +99,16 @@
   strOption
   (  long "color"
   <> short 'c'
-  <> help "Set the background color of the tray"
+  <> help "Set the background color of the tray; See https://developer.gnome.org/gdk3/stable/gdk3-RGBA-Colors.html#gdk-rgba-parse for acceptable values"
   <> metavar "COLOR"
-  <> value "000000"
+  <> value "#000000"
   )
 
 expandP :: Parser Bool
 expandP =
   switch
   (  long "expand"
-  <> help "Whether to let icons expand into the space allocated to the tray"
+  <> help "Let icons expand into the space allocated to the tray"
   <> short 'e'
   )
 
@@ -113,16 +116,24 @@
 startWatcherP =
   switch
   (  long "watcher"
-  <> help "Whether to start a Watcher to handle SNI registration"
+  <> help "Start a Watcher to handle SNI registration if one does not exist"
   <> short 'w'
   )
 
+barLengthP :: Parser Rational
+barLengthP =
+  option auto
+  (  long "length"
+  <> help "Set the proportion of the screen that the tray bar should occupy -- values are parsed as haskell rationals (e.g. 1 % 2)"
+  <> value 1
+  )
+
 getColor colorString = do
   rgba <- Gdk.newZeroRGBA
   colorParsed <- Gdk.rGBAParse rgba (T.pack colorString)
   unless colorParsed $ do
     logM "StatusNotifier.Tray" WARNING "Failed to parse provided color"
-    void $ Gdk.rGBAParse rgba "000000"
+    void $ Gdk.rGBAParse rgba "#000000"
   return rgba
 
 buildWindows :: StrutPosition
@@ -134,8 +145,9 @@
              -> String
              -> Bool
              -> Bool
+             -> Rational
              -> IO ()
-buildWindows pos align size padding monitors priority colorString expand startWatcher = do
+buildWindows pos align size padding monitors priority colorString expand startWatcher length = do
   Gtk.init Nothing
   logger <- getLogger "StatusNotifier"
   saveGlobalLogger $ setLevel priority logger
@@ -154,7 +166,7 @@
            , strutXPadding = padding
            , strutYPadding = padding
            }
-      defaultRatio = ScreenRatio (4 % 5)
+      defaultRatio = ScreenRatio length
       configBase = case pos of
              TopPos -> c1
                        { strutHeight = ExactSize size
@@ -184,6 +196,7 @@
                     , trayHost = host
                     , trayImageSize = Expand
                     , trayIconExpand = expand
+                    , trayAlignment = align
                     }
         window <- Gtk.windowNew Gtk.WindowTypeToplevel
         setupStrutWindow config window
@@ -200,11 +213,18 @@
 
 parser :: Parser (IO ())
 parser = buildWindows <$> positionP <*> alignmentP <*> sizeP <*> paddingP <*>
-         monitorNumberP <*> logP <*> colorP <*> expandP <*> startWatcherP
+         monitorNumberP <*> logP <*> colorP <*> expandP <*> startWatcherP <*> barLengthP
 
+versionOption :: Parser (a -> a)
+versionOption = infoOption
+                (printf "gtk-sni-tray-standalone %s" $ showVersion version)
+                (  long "version"
+                <> help "Show the version number of gtk-sni-tray"
+                )
+
 main :: IO ()
-main = do
-  -- TODO: start watcher if it doesn't exist
-  join $ execParser $ info (parser <**> helper)
+main =
+  join $ execParser $ info (helper <*> versionOption <*> parser)
                (  fullDesc
-               <> progDesc "Run a standalone StatusNotifierItem/AppIndicator tray")
+               <> progDesc "Run a standalone StatusNotifierItem/AppIndicator tray"
+               )
diff --git a/gtk-sni-tray.cabal b/gtk-sni-tray.cabal
--- a/gtk-sni-tray.cabal
+++ b/gtk-sni-tray.cabal
@@ -1,11 +1,11 @@
--- This file has been generated from package.yaml by hpack version 0.27.0.
+-- This file has been generated from package.yaml by hpack version 0.28.2.
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 5b235b7f79be706daee2b55416bfcd57ccbe4b938c9a8946952054d97c72d088
+-- hash: 5149f18836bd55f1519c1276fc60966cb14c7dac91cf0be093c3fa8d68be6377
 
 name:           gtk-sni-tray
-version:        0.1.0.0
+version:        0.1.1.0
 synopsis:       A standalone StatusNotifierItem/AppIndicator tray
 description:    Please see the README on Github at <https://github.com/IvanMalison/gtk-sni-tray#readme>
 category:       System
@@ -18,7 +18,6 @@
 license-file:   LICENSE
 build-type:     Simple
 cabal-version:  >= 1.10
-
 extra-source-files:
     ChangeLog.md
     README.md
@@ -45,6 +44,9 @@
     , gi-gdkpixbuf >=2.0.15
     , gi-glib
     , gi-gtk >=3.0.21
+    , gtk-strut
+    , haskell-gi >=0.21.2
+    , haskell-gi-base >=0.21.1
     , hslogger
     , status-notifier-item >=0.2.0.0 && <0.3.0.0
     , text
diff --git a/src/StatusNotifier/Tray.hs b/src/StatusNotifier/Tray.hs
--- a/src/StatusNotifier/Tray.hs
+++ b/src/StatusNotifier/Tray.hs
@@ -5,11 +5,9 @@
 import           Control.Monad
 import           Control.Monad.Trans.Class
 import           Control.Monad.Trans.Maybe
-import           Control.Monad.Trans.Reader
 import           DBus.Client
 import qualified DBus.Internal.Types as DBusTypes
 import qualified Data.ByteString as BS
-import           Data.ByteString.Unsafe
 import           Data.Coerce
 import           Data.Int
 import           Data.List
@@ -17,32 +15,28 @@
 import           Data.Maybe
 import           Data.Ord
 import qualified Data.Text as T
-import           Foreign.Ptr
 import qualified GI.DbusmenuGtk3.Objects.Menu as DM
 import qualified GI.GLib as GLib
 import           GI.GLib.Structs.Bytes
 import qualified GI.Gdk as Gdk
 import           GI.Gdk.Enums
 import           GI.Gdk.Objects.Screen
-import           GI.GdkPixbuf.Callbacks
 import           GI.GdkPixbuf.Enums
 import           GI.GdkPixbuf.Objects.Pixbuf
-import           GI.GdkPixbuf.Structs.Pixdata
 import qualified GI.Gtk as Gtk
 import           GI.Gtk.Flags
-import qualified GI.Gtk.Objects.Box as Gtk
-import qualified GI.Gtk.Objects.HBox as Gtk
 import           GI.Gtk.Objects.IconTheme
+import           Graphics.UI.GIGtkStrut
 import           StatusNotifier.Host.Service
 import qualified StatusNotifier.Item.Client as IC
-import           StatusNotifier.Util
 import           System.Directory
 import           System.Log.Logger
-import           System.Posix.Process
 import           Text.Printf
 
+trayLogger :: Priority -> String -> IO ()
 trayLogger = logM "StatusNotifier.Tray"
 
+themeLoadFlags :: [IconLookupFlags]
 themeLoadFlags = [IconLookupFlagsGenericFallback, IconLookupFlagsUseBuiltin]
 
 getThemeWithDefaultFallbacks :: String -> IO IconTheme
@@ -50,7 +44,7 @@
   themeForIcon <- iconThemeNew
   defaultTheme <- iconThemeGetDefault
 
-  runMaybeT $ do
+  _ <- runMaybeT $ do
     screen <- MaybeT screenGetDefault
     lift $ iconThemeSetScreen themeForIcon screen
 
@@ -102,18 +96,20 @@
   , trayOrientation :: Gtk.Orientation
   , trayImageSize :: TrayImageSize
   , trayIconExpand :: Bool
+  , trayAlignment :: StrutAlignment
   }
 
 buildTray :: TrayParams -> IO Gtk.Box
 buildTray TrayParams { trayHost = Host
                        { itemInfoMap = getInfoMap
-                       , addUpdateHandler = addHandler
-                       , removeUpdateHandler = removeHandler
+                       , addUpdateHandler = addUHandler
+                       , removeUpdateHandler = removeUHandler
                        }
                      , trayClient = client
                      , trayOrientation = orientation
                      , trayImageSize = imageSize
                      , trayIconExpand = shouldExpand
+                     , trayAlignment = alignment
                      } = do
   trayLogger INFO "Building tray"
 
@@ -126,7 +122,7 @@
         case orientation of
           Gtk.OrientationHorizontal ->
             Gdk.getRectangleHeight rectangle
-          Gtk.OrientationVertical ->
+          _ ->
             Gdk.getRectangleWidth rectangle
 
       getInfo def name = fromMaybe def . Map.lookup name <$> getInfoMap
@@ -154,7 +150,7 @@
           let serviceNameStr = coerce serviceName
               servicePathStr = coerce servicePath :: String
               serviceMenuPathStr = coerce <$> pathForMenu
-              logText = printf "Adding widget for %s - %s."
+              logText = printf "Adding widget for %s - %s"
                         serviceNameStr servicePathStr
 
           trayLogger INFO logText
@@ -164,19 +160,26 @@
           image <-
             case imageSize of
               Expand -> do
-                traySize <- Gtk.widgetGetAllocation trayBox >>= getSize
-                image <- getScaledPixBufFromInfo traySize info >>= Gtk.imageNewFromPixbuf
+                image <- Gtk.imageNew
                 let setPixbuf rectangle =
                       do
                         size <- getSize rectangle
                         pixBuf <- getInfo info serviceName >>= getScaledPixBufFromInfo size
                         Gtk.imageSetFromPixbuf image pixBuf
-                Gtk.onWidgetSizeAllocate image setPixbuf
+                        trayLogger INFO $ printf "Setting size to %s" $ show size
+
+                        allocation <- Gtk.widgetGetAllocation image
+                        actualWidth <- Gdk.getRectangleWidth allocation
+                        actualHeight <- Gdk.getRectangleHeight allocation
+                        when (actualWidth /= size || actualHeight /= size) $ do
+                             Gtk.widgetSetSizeRequest image size size
+                             trayLogger INFO $ printf "Actual width %s" $ show actualWidth
+                             Gtk.containerResizeChildren trayBox
+                _ <- Gtk.onWidgetSizeAllocate image setPixbuf
                 return image
               TrayImageSize size -> do
                 pixBuf <- getScaledPixBufFromInfo size info
-                image <- Gtk.imageNewFromPixbuf pixBuf
-                return image
+                Gtk.imageNewFromPixbuf pixBuf
 
           Gtk.containerAdd button image
 
@@ -196,13 +199,18 @@
                 maybe activateItem popupItemForMenu maybeMenu >> return False
               activateItem = void $ IC.activate client serviceName servicePath 0 0
 
-          Gtk.onWidgetButtonPressEvent button $ const popupItemMenu
+          _ <- Gtk.onWidgetButtonPressEvent button $ const popupItemMenu
 
           MV.modifyMVar_ contextMap $ return . Map.insert serviceName context
 
           Gtk.widgetShowAll button
-          Gtk.boxPackStart trayBox button shouldExpand True 0
+          let packFn =
+                case alignment of
+                  End -> Gtk.boxPackEnd
+                  _ -> Gtk.boxPackStart
 
+          packFn trayBox button shouldExpand True 0
+
       updateHandler ItemRemoved ItemInfo { itemServiceName = name }
         = getContext name >>= removeWidget
         where removeWidget Nothing =
@@ -256,6 +264,6 @@
         void $ Gdk.threadsAddIdle GLib.PRIORITY_DEFAULT $
              updateHandler updateType info >> return False
 
-  handlerId <- addHandler uiUpdateHandler
-  _ <- Gtk.onWidgetDestroy trayBox $ removeHandler handlerId
+  handlerId <- addUHandler uiUpdateHandler
+  _ <- Gtk.onWidgetDestroy trayBox $ removeUHandler handlerId
   return trayBox
