使用rust編寫dwm status-bar應用程式

rcxid發表於2021-09-10

dwm是linux系統下的一款使用c語言編寫的視窗管理器,dwm的特點就是小,核心程式碼只有幾千行,編譯後可執行檔案也僅有幾十KB,dwm不支援配置檔案,每次對dwm進行修改,例如字型顯示大小,只能通過修改原始碼,重新編譯。

dwm預設狀態列十分簡單,如下所示,預設情況下status只顯示dwm的版本號,使用者一般通過shell指令碼讓狀態列顯示更多的資訊,例如時間、電量、網速等資訊。接下來我們將使用rust編寫dwm status-bar應用。

    +------+----------------------------------+--------+
    | tags | title                            | status +
    +------+---------------------+------------+--------+
    |                            |                     |
    |                            |                     |
    |                            |                     |
    |                            |                     |
    |          master            |        stack        |
    |                            |                     |
    |                            |                     |
    |                            |                     |
    |                            |                     |
    +----------------------------+---------------------+
  • 通過以下命令可以設定dwm狀態列資訊

    ❯ xsetroot -name "$(date)"
  • 建立一個rust專案

    ❯ cargo new status-bar
  • 編寫一個可以執行linux命令的函式,如果你的linux系統沒有dash shell,可以安裝一個或者把下面程式碼中的dash改為bash

    pub fn exec_cmd(command: &str) -> Result<String, FromUtf8Error> {
      let output = Command::new("/bin/dash")
          .arg("-c")
          .arg(command)
          .output()
          .expect("error");
      let result = String::from_utf8(output.stdout);
      result
    }

接下來以電池資訊獲取舉例

  • 建立電池結構體,電池圖示可以去nerd font官網找以下

    pub struct Battery {
      // 電池圖示
      icon: Vec<String>,
      // 電池電量等級
      level: usize,
      // 是否充電
      charge: bool,
      // 電池電量
      quantity: usize,
      // 更新時間
      timestamp: u64,
    }
  • 獲取電池充電資訊

      // 獲取電池狀態,通過讀取系統檔案內容獲取充電狀態
      fn get_battery_status() -> bool {
          let charge: bool;
          let result = fs::read_to_string("/sys/class/power_supply/BAT0/status");
          match result {
              Ok(content) => {
                  if content.contains("Charging") {
                      charge = true;
                  } else {
                      charge = false;
                  }
              },
              Err(err) => {
                  charge = true;
                  eprintln!("get battery status failed: {}", err);
              },
          }
          charge
      }
  • 獲取電池電量

      // 獲取電池電量,通過讀取系統檔案獲取電量資訊
      fn get_battery_quantity() -> usize {
          let quantity: usize;
          let result = fs::read_to_string("/sys/class/power_supply/BAT0/capacity");
          match result {
              Ok(content) => {
                  quantity = content.replace("\n", "").parse().unwrap();
              },
              Err(err) => {
                  quantity = 100;
                  eprintln!("get battery quantity failed: {}", err);
              },
          }
          quantity
      }
  • 電池的這兩個狀態,充電狀態需要頻繁更新,但是電量更新一般不需要過於頻繁

      fn update(&mut self) {
          self.charge = Battery::get_battery_status();
          let current = util::timestamp();
          // 通過上次更新時間戳和當前時間對比判斷是否更新電量資訊
          if current - self.timestamp > UPDATE_RATE {
              self.quantity = Battery::get_battery_quantity();
              self.level = (self.quantity + 10) / 25;
              self.timestamp = current;
          }
      }
  • 將獲取的資訊展示到dwm狀態列,這裡用到了之前寫的執行linux命令方法

    // 設定狀態列
    pub fn set_bar(msg: &String) {
      let cmd = format!("xsetroot -name ' {} '", msg.replace("\n", ""));
      let res = exec_cmd(cmd.as_str());
      match res {
          Ok(_) => {}
          Err(err) => {
              eprintln!("xsetroot error, err is {}", err);
          }
      }
    }

    這個小專案是我學習rust的時候寫的,我認為通過寫專案是學習一本程式語言最快的方法。本文只是簡單介紹了dwm狀態列這個小軟體的設計思路,具體程式碼大家可以去我的gitee主頁檢視。
    status-bar: gitee.com/rcxid/status-bar.git

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章