gtk-sni-tray 0.1.0.0 → 0.1.1.0
raw patch · 4 files changed
+78/−43 lines, 4 filesdep +haskell-gidep +haskell-gi-base
Dependencies added: haskell-gi, haskell-gi-base
Files
- README.md +7/−2
- app/Main.hs +34/−14
- gtk-sni-tray.cabal +6/−4
- src/StatusNotifier/Tray.hs +31/−23
README.md view
@@ -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.
app/Main.hs view
@@ -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"+ )
gtk-sni-tray.cabal view
@@ -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
src/StatusNotifier/Tray.hs view
@@ -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