module Graphics.UI.GIGtkStrut where import Control.Monad import Control.Monad.IO.Class import Control.Monad.Fail (MonadFail) import Control.Monad.Trans.Class import Control.Monad.Trans.Maybe import Data.Int import Data.Maybe import qualified Data.Text as T import qualified GI.Gdk as Gdk import qualified GI.Gtk as Gtk import Graphics.UI.EWMHStrut data StrutPosition = TopPos | BottomPos | LeftPos | RightPos deriving (Show, Read, Eq) data StrutAlignment = Beginning | Center | End deriving (Show, Read, Eq) data StrutSize = ExactSize Int32 | ScreenRatio Rational deriving (Show, Read, Eq) data StrutConfig = StrutConfig { strutWidth :: StrutSize , strutHeight :: StrutSize , strutXPadding :: Int32 , strutYPadding :: Int32 , strutMonitor :: Maybe Int32 , strutPosition :: StrutPosition , strutAlignment :: StrutAlignment , strutDisplayName :: Maybe T.Text } deriving (Show, Eq) defaultStrutConfig = StrutConfig { strutWidth = ScreenRatio 1 , strutHeight = ScreenRatio 1 , strutXPadding = 0 , strutYPadding = 0 , strutMonitor = Nothing , strutPosition = TopPos , strutAlignment = Beginning , strutDisplayName = Nothing } buildStrutWindow :: (MonadFail m, MonadIO m) => StrutConfig -> m Gtk.Window buildStrutWindow config = do window <- Gtk.windowNew Gtk.WindowTypeToplevel setupStrutWindow config window return window setupStrutWindow :: (MonadFail m, MonadIO m) => StrutConfig -> Gtk.Window -> m () setupStrutWindow StrutConfig { strutWidth = widthSize , strutHeight = heightSize , strutXPadding = xpadding , strutYPadding = ypadding , strutMonitor = monitorNumber , strutPosition = position , strutAlignment = alignment , strutDisplayName = displayName } window = do Just display <- maybe Gdk.displayGetDefault Gdk.displayOpen displayName Just monitor <- maybe (Gdk.displayGetPrimaryMonitor display) (Gdk.displayGetMonitor display) monitorNumber screen <- Gdk.displayGetDefaultScreen display monitorCount <- Gdk.displayGetNMonitors display allMonitors <- catMaybes <$> mapM (Gdk.displayGetMonitor display) [0..(monitorCount-1)] allGeometries <- mapM Gdk.monitorGetGeometry allMonitors let getFullY geometry = (+) <$> Gdk.getRectangleY geometry <*> Gdk.getRectangleHeight geometry getFullX geometry = (+) <$> Gdk.getRectangleX geometry <*> Gdk.getRectangleWidth geometry screenWidth <- maximum <$> mapM getFullX allGeometries screenHeight <- maximum <$> mapM getFullY allGeometries Gtk.windowSetTypeHint window Gdk.WindowTypeHintDock geometry <- Gdk.newZeroGeometry monitorGeometry <- Gdk.monitorGetGeometry monitor monitorWidth <- Gdk.getRectangleWidth monitorGeometry monitorHeight <- Gdk.getRectangleHeight monitorGeometry monitorX <- Gdk.getRectangleX monitorGeometry monitorY <- Gdk.getRectangleY monitorGeometry let width = case widthSize of ExactSize w -> w ScreenRatio p -> floor $ p * fromIntegral (monitorWidth - (2 * xpadding)) height = case heightSize of ExactSize h -> h ScreenRatio p -> floor $ p * fromIntegral (monitorHeight - (2 * ypadding)) Gdk.setGeometryBaseWidth geometry width Gdk.setGeometryBaseHeight geometry height Gdk.setGeometryMinWidth geometry width Gdk.setGeometryMinHeight geometry height Gdk.setGeometryMaxWidth geometry width Gdk.setGeometryMaxHeight geometry height Gtk.windowSetGeometryHints window (Nothing :: Maybe Gtk.Window) (Just geometry) allHints let paddedHeight = height + 2 * ypadding paddedWidth = width + 2 * xpadding getAlignedPos dimensionPos dpadding monitorSize barSize = dimensionPos + case alignment of Beginning -> dpadding Center -> (monitorSize - barSize) `div` 2 End -> monitorSize - barSize - dpadding xAligned = getAlignedPos monitorX xpadding monitorWidth width yAligned = getAlignedPos monitorY ypadding monitorHeight height (xPos, yPos) = case position of TopPos -> (xAligned, monitorY + ypadding) BottomPos -> (xAligned, monitorY + monitorHeight - height - ypadding) LeftPos -> (monitorX + xpadding, yAligned) RightPos -> (monitorX + monitorWidth - width - xpadding, yAligned) Gtk.windowSetScreen window screen Gtk.windowMove window xPos yPos Gtk.windowSetKeepBelow window True let ewmhSettings = case position of TopPos -> zeroStrutSettings { _top = monitorY + paddedHeight , _top_start_x = xPos - xpadding , _top_end_x = xPos + width + xpadding - 1 } BottomPos -> zeroStrutSettings { _bottom = screenHeight - monitorY - monitorHeight + paddedHeight , _bottom_start_x = xPos - xpadding , _bottom_end_x = xPos + width + xpadding - 1 } LeftPos -> zeroStrutSettings { _left = monitorX + paddedWidth , _left_start_y = yPos - ypadding , _left_end_y = yPos + height + ypadding - 1 } RightPos -> zeroStrutSettings { _right = screenWidth - monitorX - monitorWidth + paddedWidth , _right_start_y = yPos - ypadding , _right_end_y = yPos + height + ypadding - 1 } setStrutProperties = void $ runMaybeT $ do gdkWindow <- MaybeT $ Gtk.widgetGetWindow window lift $ setStrut gdkWindow ewmhSettings void $ Gtk.onWidgetRealize window setStrutProperties allHints :: [Gdk.WindowHints] allHints = [ Gdk.WindowHintsMinSize , Gdk.WindowHintsMaxSize , Gdk.WindowHintsBaseSize , Gdk.WindowHintsUserPos , Gdk.WindowHintsUserSize ]