module System.Taffybar.Widget.Util where
import Control.Concurrent ( forkIO )
import Control.Monad ( when, forever, void )
import Control.Monad.IO.Class
import Control.Monad.Trans.Maybe
import Data.Functor ( ($>) )
import Data.Int
import qualified Data.Text as T
import Data.Tuple.Sequence
import qualified GI.GdkPixbuf.Objects.Pixbuf as GI
import qualified GI.GdkPixbuf.Objects.Pixbuf as PB
import qualified GI.Gtk
import Graphics.UI.Gtk as Gtk
import Graphics.UI.Gtk.General.StyleContext
import System.Directory
import System.FilePath.Posix
import System.Taffybar.Information.XDG.DesktopEntry
import System.Taffybar.Util
import Text.Printf
import Paths_taffybar ( getDataDir )
onClick :: [Click]
-> IO a
-> EventM EButton Bool
onClick triggers action = tryEvent $ do
click <- eventClick
when (click `elem` triggers) $ void $ liftIO action
attachPopup :: (WidgetClass w, WindowClass wnd) =>
w
-> String
-> wnd
-> IO ()
attachPopup widget title window = do
set window [ windowTitle := title
, windowTypeHint := WindowTypeHintTooltip
, windowSkipTaskbarHint := True
, windowSkipPagerHint := True
, windowTransientFor :=> getWindow
]
windowSetKeepAbove window True
windowStick window
where getWindow = do
Just topLevelWindow <- fmap castToWindow <$> widgetGetAncestor widget gTypeWindow
return topLevelWindow
displayPopup :: (WidgetClass w, WindowClass wnd) =>
w
-> wnd
-> IO ()
displayPopup widget window = do
windowSetPosition window WinPosMouse
(x, y ) <- windowGetPosition window
(_, y') <- widgetGetSizeRequest widget
widgetShowAll window
if y > y'
then windowMove window x (y - y')
else windowMove window x y'
widgetGetAllocatedSize
:: (WidgetClass self, MonadIO m)
=> self -> m (Int, Int)
widgetGetAllocatedSize widget =
liftIO $
sequenceT (widgetGetAllocatedWidth widget, widgetGetAllocatedHeight widget)
colorize :: String
-> String
-> String
-> String
colorize fg bg = printf "<span%s%s>%s</span>" (attr "fg" fg) (attr "bg" bg)
where attr name value
| null value = ""
| otherwise = printf " %scolor=\"%s\"" name value
backgroundLoop :: IO a -> IO ()
backgroundLoop = void . forkIO . forever
drawOn :: WidgetClass object => object -> IO () -> IO object
drawOn drawArea action = on drawArea realize action $> drawArea
widgetSetClass
:: (Gtk.WidgetClass widget, MonadIO m)
=> widget -> String -> m widget
widgetSetClass widget klass = liftIO $ do
context <- Gtk.widgetGetStyleContext widget
styleContextAddClass context klass
return widget
widgetSetClassGI :: (GI.Gtk.IsWidget b, MonadIO m) => b -> T.Text -> m b
widgetSetClassGI widget klass =
GI.Gtk.widgetGetStyleContext widget >>=
flip GI.Gtk.styleContextAddClass klass >> return widget
themeLoadFlags :: [GI.Gtk.IconLookupFlags]
themeLoadFlags =
[ GI.Gtk.IconLookupFlagsGenericFallback
, GI.Gtk.IconLookupFlagsUseBuiltin
]
getImageForDesktopEntry :: Int32 -> DesktopEntry -> IO (Maybe GI.Pixbuf)
getImageForDesktopEntry size entry = runMaybeT $ do
iconName <- MaybeT $ return $ deIcon entry
let iconNameText = T.pack iconName
MaybeT $ do
iconTheme <- GI.Gtk.iconThemeGetDefault
hasIcon <- GI.Gtk.iconThemeHasIcon iconTheme iconNameText
logPrintFDebug "System.Taffybar.Widget.Util" "Entry: %s" entry
logPrintFDebug "System.Taffybar.Widget.Util" "Icon present: %s" hasIcon
if hasIcon
then
GI.Gtk.iconThemeLoadIcon iconTheme iconNameText size themeLoadFlags
else do
exists <- doesFileExist iconName
if isAbsolute iconName && exists
then Just <$> GI.pixbufNewFromFile iconName
else return Nothing
loadPixbufByName :: Int32 -> T.Text -> IO (Maybe GI.Pixbuf)
loadPixbufByName size name = do
iconTheme <- GI.Gtk.iconThemeGetDefault
hasIcon <- GI.Gtk.iconThemeHasIcon iconTheme name
if hasIcon
then GI.Gtk.iconThemeLoadIcon iconTheme name size themeLoadFlags
else return Nothing
alignCenter :: (GI.Gtk.IsWidget o, MonadIO m) => o -> m ()
alignCenter widget =
GI.Gtk.setWidgetValign widget GI.Gtk.AlignCenter >>
GI.Gtk.setWidgetHalign widget GI.Gtk.AlignCenter
vFillCenter :: (GI.Gtk.IsWidget o, MonadIO m) => o -> m ()
vFillCenter widget =
GI.Gtk.widgetSetVexpand widget True >>
GI.Gtk.setWidgetValign widget GI.Gtk.AlignFill >>
GI.Gtk.setWidgetHalign widget GI.Gtk.AlignCenter
pixbufNewFromFileAtScaleByHeight :: Int32 -> String -> IO PB.Pixbuf
pixbufNewFromFileAtScaleByHeight height name =
PB.pixbufNewFromFileAtScale name (-1) height True
loadIcon :: Int32 -> String -> IO PB.Pixbuf
loadIcon height name =
((</> "icons" </> name) <$> getDataDir) >>=
pixbufNewFromFileAtScaleByHeight height
setMinWidth :: (Gtk.WidgetClass w, MonadIO m) => Int -> w -> m w
setMinWidth width widget = liftIO $ do
Gtk.widgetSetSizeRequest widget width (-1)
return widget