2012-06-15 25 views
5

Tôi đang sử dụng dynamicLogWithPP từ XMonad.Hooks.DynamicLog cùng với dzen2 làm thanh trạng thái trong xmonad. Một trong những điều tôi muốn được hiển thị trên thanh là thời gian còn lại trong bản nhạc đang phát ở chế độ táo bạo (nếu có). Nhận được thông tin này rất dễ dàng:logHook của xmonad có thể chạy trong khoảng thời gian được đặt thay vì trả lời (chỉ đơn thuần) cho các sự kiện bố cục không?

audStatus :: Player -> X (Maybe String) 
audStatus p = do 
    info <- liftIO $ tryS $ withPlayer p $ do 
       ispaused <- paused 
       md <- getMetadataString 
       timeleftmillis <- (-) <$> (getCurrentTrack >>= songFrames) <*> time 
       let artist = md ! "artist" 
        title = md ! "title" 
        timeleft = timeleftmillis `quot` 1000 
        (minutes, seconds) = timeleft `quotRem` 60 
        disp = artist ++ " - " ++ title ++ " (-"++(show minutes)++":"++(show seconds)++")" -- will be wrong if seconds < 10 
        audcolor False = dzenColor base0 base03 
        audcolor True = dzenColor base1 base02 
       return $ wrap "^ca(1, pms p)" "^ca()" (audcolor ispaused disp) 
    return $ either (const Nothing) Just info 

Vì vậy, tôi có thể dính rằng trong ppExtras và nó hoạt động tốt — trừ nó chỉ được chạy khi logHook được chạy, và điều đó chỉ xảy ra khi một sự kiện phù hợp đi xuống pike . Vì vậy, màn hình có khả năng tĩnh trong một thời gian dài, cho đến khi tôi (ví dụ) chuyển đổi không gian làm việc.

Dường như một số người chỉ chạy hai thanh dzen, với một đầu ra nhận được từ một tập lệnh shell. Đó có phải là cách duy nhất để cập nhật thường xuyên không? Hoặc điều này có thể được thực hiện từ bên trong xmonad (mà không nhận được quá điên/hacky)?

ETA: Tôi cố gắng này, mà dường như như thể nó sẽ làm việc tốt hơn so với nó:

  1. tạo TChan các bản cập nhật từ xmonad, và một cho cập nhật từ một chức năng bỏ phiếu Audacious;
  2. đặt trường ppOutput trong cấu trúc PP từ DynamicLog để ghi vào TChan đầu tiên;
  3. ngã ba chức năng bỏ phiếu táo bạo và ghi nó vào TChan thứ hai;
  4. chia nhỏ một chức năng để đọc từ cả hai TChans (kiểm tra xem chúng có trống không, trước tiên) và kết hợp đầu ra.

Cập nhật từ XMonad được đọc từ kênh và xử lý kịp thời nhưng cập nhật từ Audacious hiếm khi được đăng ký ở tất cả — cứ 5 giây một lần. Dường như một số cách tiếp cận dọc theo những dòng này phải làm việc.

+0

Tôi đã cập nhật câu trả lời của mình với một chút giải thích về lý do giải pháp 'TChan' được đề xuất của bạn - và các giải pháp khác dựa trên việc có nhiều luồng - không hoạt động đúng cách. –

+0

Cảm ơn bạn đã cập nhật. –

Trả lời

6

Tôi biết đây là một câu hỏi cũ, nhưng tôi đến đây tìm kiếm câu trả lời cho điều này cách đây vài ngày, và tôi nghĩ tôi sẽ chia sẻ cách tôi giải quyết nó. Bạn thực sự có thể làm điều đó hoàn toàn từ xmonad. Đó là một chút hacky nhỏ, nhưng tôi nghĩ rằng nó đẹp hơn nhiều so với bất kỳ lựa chọn thay thế tôi đã đi qua.

Về cơ bản, tôi đã sử dụng thư viện XMonad.Util.Timer, sẽ gửi sự kiện X sau một khoảng thời gian cụ thể (trong trường hợp này, một giây).Sau đó, tôi chỉ cần viết một móc sự kiện cho nó, mà bắt đầu hẹn giờ một lần nữa, và sau đó chạy thủ công móc đăng nhập.

Tôi cũng phải sử dụng thư viện XMonad.Util.ExtensibleState, vì Bộ hẹn giờ sử dụng biến id để đảm bảo nó phản hồi đúng sự kiện, vì vậy tôi phải lưu biến đó giữa các sự kiện.

Dưới đây là mã của tôi:

{-# LANGUAGE DeriveDataTypeable #-} 

import qualified XMonad.Util.ExtensibleState as XS 
import XMonad.Util.Timer 

... 

-- wrapper for the Timer id, so it can be stored as custom mutable state 
data TidState = TID TimerId deriving Typeable 

instance ExtensionClass TidState where 
    initialValue = TID 0 

... 

-- put this in your startupHook 
-- start the initial timer, store its id 
clockStartupHook = startTimer 1 >>= XS.put . TID 

-- put this in your handleEventHook 
clockEventHook e = do    -- e is the event we've hooked 
    (TID t) <- XS.get     -- get the recent Timer id 
    handleTimer t e $ do    -- run the following if e matches the id 
    startTimer 1 >>= XS.put . TID -- restart the timer, store the new id 
    ask >>= logHook.config   -- get the loghook and run it 
    return Nothing     -- return required type 
    return $ All True     -- return required type 

Khá đơn giản. Tôi hy vọng điều này là hữu ích cho một ai đó.

+0

Đối với bất kỳ ai sử dụng mã này, bạn cũng phải 'nhập dữ liệu.Monoid' – user316146

+0

Điều này phá vỡ khả năng khởi động lại xmonad cho tôi: Tôi giả định quá trình khởi động lại không thể xử lý sự kiện từ quá trình cũ (không chắc chắn cách những người này tồn tại quá trình khởi động lại mặc dù). Tôi đã phải mở rộng nó để ngừng bắn khi tắt máy đã được bắt đầu và chờ cho đến khi sự kiện cuối cùng đã được xử lý trong khi tắt máy. – akosch

+0

@akosch Oh wow, tôi quên mất câu hỏi này. Có, nó cũng giúp tôi không thể khởi động lại và tôi đã thay đổi thiết lập cá nhân của mình kể từ khi tôi đăng câu trả lời này. Ngày nay tôi có một cá thể Conky gửi một sự kiện X tới xmonad mỗi giây một lần. Sự kiện chứa thông tin phần cứng, mà tôi cũng hiển thị trong dzen, nhưng vấn đề là tôi đang sử dụng một chương trình bên ngoài để kích hoạt cập nhật ngay bây giờ. Nhưng nếu bạn nhận được nó làm việc với khởi động lại, có lẽ câu trả lời nên được cập nhật với mã của bạn? – DarthFennec

2

Nó không thể được thực hiện từ bên trong xmonad; mô hình luồng hiện tại của xmonad hơi thiếu (và do đó là của dzen). Tuy nhiên, bạn có thể bắt đầu một quá trình riêng biệt, định kỳ thăm dò ý kiến ​​trình phát nhạc của bạn và sau đó sử dụng một trong các bộ ghép kênh dzen (ví dụ: dmplex) để kết hợp đầu ra từ hai quy trình.

Bạn cũng có thể muốn xem xét xmobartaffybar, cả hai đều có câu chuyện tốt hơn so với dzen.

Liên quan đến lý do giải pháp TChan được đề xuất của bạn không hoạt động đúng cách, bạn có thể muốn đọc các phần "Quy ước", "Nhập ngoại" và "Thời gian chạy không có luồng" tại my crash course on the FFI and gtk, lưu ý rằng xmonad hiện đang sử dụng thời gian chạy không phải luồng của GHC. Câu trả lời ngắn gọn là vòng lặp chính của xmonad thực hiện cuộc gọi FFI tới Xlib chờ đợi một sự kiện X; cuộc gọi này chặn tất cả các chủ đề Haskell khác chạy cho đến khi nó trở lại.