fix: patch kanshi-sni reconnect handling
This commit is contained in:
96
nixos/patches/kanshi-sni-refresh-and-reconnect.patch
Normal file
96
nixos/patches/kanshi-sni-refresh-and-reconnect.patch
Normal file
@@ -0,0 +1,96 @@
|
||||
--- a/src/Kanshi/SNI.hs
|
||||
+++ b/src/Kanshi/SNI.hs
|
||||
@@ -28,6 +28,7 @@
|
||||
, castPtrToStablePtr
|
||||
)
|
||||
import System.Directory (XdgDirectory(..), doesDirectoryExist, getXdgDirectory)
|
||||
+import System.FilePath (takeFileName)
|
||||
import System.FSNotify (Event(..), withManager, watchDir)
|
||||
import System.IO.Unsafe (unsafePerformIO)
|
||||
|
||||
@@ -46,6 +47,9 @@
|
||||
, sniGLibContext :: GLib.MainContext
|
||||
}
|
||||
|
||||
+refreshIntervalMicros :: Int
|
||||
+refreshIntervalMicros = 5 * 1000000
|
||||
+
|
||||
startSNI :: IO ()
|
||||
startSNI = do
|
||||
let busName = "org.kanshi.SNI"
|
||||
@@ -96,12 +100,17 @@
|
||||
dirExists <- doesDirectoryExist configDir
|
||||
when dirExists $
|
||||
void $ forkIO $ withManager $ \mgr -> do
|
||||
- void $ watchDir mgr configDir (const True) $ \event ->
|
||||
+ void $ watchDir mgr configDir (\event -> takeFileName (eventPath event) == "config") $ \event ->
|
||||
case event of
|
||||
- Modified {} -> refreshState sniState
|
||||
- Added {} -> refreshState sniState
|
||||
+ Modified {} -> safeRefreshState sniState
|
||||
+ Added {} -> safeRefreshState sniState
|
||||
+ Removed {} -> safeRefreshState sniState
|
||||
_ -> pure ()
|
||||
forever $ threadDelay maxBound
|
||||
+
|
||||
+ void $ forkIO $ forever $ do
|
||||
+ threadDelay refreshIntervalMicros
|
||||
+ safeRefreshState sniState
|
||||
|
||||
-- Block forever on main thread
|
||||
forever $ threadDelay maxBound
|
||||
@@ -171,9 +180,29 @@
|
||||
runOnGLibMain (sniGLibContext sniState) $
|
||||
Dbusmenu.serverSetRoot (sniMenuServer sniState) newRoot
|
||||
|
||||
+safeRefreshState :: SNIState -> IO ()
|
||||
+safeRefreshState sniState =
|
||||
+ refreshState sniState `catch` \(_ :: SomeException) -> do
|
||||
+ resetConnection sniState `catch` \(_ :: SomeException) -> pure ()
|
||||
+ refreshState sniState `catch` \(_ :: SomeException) -> pure ()
|
||||
+
|
||||
+ensureUsableConnection :: Maybe KanshiConnection -> IO (Maybe KanshiConnection)
|
||||
+ensureUsableConnection mConn =
|
||||
+ case mConn of
|
||||
+ Nothing -> tryConnect
|
||||
+ Just conn -> do
|
||||
+ statusResult <- kanshiStatus conn
|
||||
+ case statusResult of
|
||||
+ Right _ -> pure (Just conn)
|
||||
+ Left _ -> do
|
||||
+ disconnectKanshi conn
|
||||
+ tryConnect
|
||||
+
|
||||
refreshState :: SNIState -> IO ()
|
||||
refreshState sniState = do
|
||||
- mConn <- readMVar (sniConnection sniState)
|
||||
+ mConn <- modifyMVar (sniConnection sniState) $ \currentConn -> do
|
||||
+ freshConn <- ensureUsableConnection currentConn
|
||||
+ pure (freshConn, freshConn)
|
||||
newState <- buildInitialState mConn
|
||||
modifyMVar_ (sniAppState sniState) $ const (pure newState)
|
||||
rebuildMenu sniState
|
||||
--- a/src/Kanshi/Varlink.hs
|
||||
+++ b/src/Kanshi/Varlink.hs
|
||||
@@ -68,11 +68,16 @@
|
||||
|
||||
varlinkCall :: KanshiConnection -> Value -> IO (Either KanshiError Value)
|
||||
varlinkCall (KanshiConnection sock) request = do
|
||||
- sendAll sock $ LBS.toStrict (encode request) <> BS.singleton 0
|
||||
- response <- recvUntilNull sock
|
||||
- case eitherDecodeStrict response of
|
||||
- Left err -> return $ Left $ ProtocolError $ "JSON decode error: " ++ err
|
||||
- Right val -> return $ parseVarlinkResponse val
|
||||
+ result <- try $ do
|
||||
+ sendAll sock $ LBS.toStrict (encode request) <> BS.singleton 0
|
||||
+ recvUntilNull sock
|
||||
+ case (result :: Either IOException BS.ByteString) of
|
||||
+ Left err ->
|
||||
+ return $ Left $ ConnectionFailed $ "Socket I/O failed: " ++ show err
|
||||
+ Right response ->
|
||||
+ case eitherDecodeStrict response of
|
||||
+ Left err -> return $ Left $ ProtocolError $ "JSON decode error: " ++ err
|
||||
+ Right val -> return $ parseVarlinkResponse val
|
||||
|
||||
recvUntilNull :: Socket -> IO BS.ByteString
|
||||
recvUntilNull sock = go BS.empty
|
||||
@@ -1,16 +1,26 @@
|
||||
{ config, inputs, pkgs, makeEnable, ... }:
|
||||
let
|
||||
system = pkgs.stdenv.hostPlatform.system;
|
||||
kanshiSniPackage =
|
||||
inputs.kanshi-sni.packages.${system}.default.overrideAttrs (old: {
|
||||
patches = (old.patches or [ ]) ++ [
|
||||
./patches/kanshi-sni-refresh-and-reconnect.patch
|
||||
];
|
||||
});
|
||||
in
|
||||
makeEnable config "myModules.sni" true {
|
||||
home-manager.sharedModules = [
|
||||
{
|
||||
systemd.user.services.kanshi-sni = {
|
||||
Unit = {
|
||||
Description = "kanshi-sni tray app";
|
||||
After = [ "graphical-session.target" "tray.target" ];
|
||||
PartOf = [ "graphical-session.target" ];
|
||||
After = [ "graphical-session.target" "tray.target" "kanshi.service" ];
|
||||
PartOf = [ "graphical-session.target" "kanshi.service" ];
|
||||
Requires = [ "tray.target" ];
|
||||
Wants = [ "kanshi.service" ];
|
||||
};
|
||||
Service = {
|
||||
ExecStart = "${inputs.kanshi-sni.packages.${pkgs.stdenv.hostPlatform.system}.default}/bin/kanshi-sni";
|
||||
ExecStart = "${kanshiSniPackage}/bin/kanshi-sni";
|
||||
Restart = "always";
|
||||
RestartSec = 3;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user