#linux #systray #api-bindings #properties

ksni

实现 KDE/freedesktop StatusNotifierItem 规范的 Rust 实现

8 个版本

0.2.2 2024 年 4 月 27 日
0.2.1 2023 年 6 月 27 日
0.2.0 2021 年 7 月 22 日
0.1.3 2021 年 3 月 20 日
0.0.0 2019 年 6 月 3 日

#62 in GUI

Download history 1319/week @ 2024-05-02 1428/week @ 2024-05-09 1683/week @ 2024-05-16 1166/week @ 2024-05-23 1972/week @ 2024-05-30 1470/week @ 2024-06-06 1123/week @ 2024-06-13 1625/week @ 2024-06-20 1377/week @ 2024-06-27 1361/week @ 2024-07-04 1264/week @ 2024-07-11 1187/week @ 2024-07-18 1529/week @ 2024-07-25 1252/week @ 2024-08-01 1339/week @ 2024-08-08 1073/week @ 2024-08-15

5,539 每月下载量
6 包中使用 (4 直接使用)

无许可证

89KB
2K SLoC

ksni

Build Status Crates Documentation MSRV

实现 KDE/freedesktop StatusNotifierItem 规范的 Rust 实现

示例

use ksni;

#[derive(Debug)]
struct MyTray {
    selected_option: usize,
    checked: bool,
}

impl ksni::Tray for MyTray {
    fn icon_name(&self) -> String {
        "help-about".into()
    }
    fn title(&self) -> String {
        if self.checked { "CHECKED!" } else { "MyTray" }.into()
    }
    // NOTE: On some system trays, `id` is a required property to avoid unexpected behaviors
    fn id(&self) -> String {
        env!("CARGO_PKG_NAME").into()
    }
    fn menu(&self) -> Vec<ksni::MenuItem<Self>> {
        use ksni::menu::*;
        vec![
            SubMenu {
                label: "a".into(),
                submenu: vec![
                    SubMenu {
                        label: "a1".into(),
                        submenu: vec![
                            StandardItem {
                                label: "a1.1".into(),
                                ..Default::default()
                            }
                            .into(),
                            StandardItem {
                                label: "a1.2".into(),
                                ..Default::default()
                            }
                            .into(),
                        ],
                        ..Default::default()
                    }
                    .into(),
                    StandardItem {
                        label: "a2".into(),
                        ..Default::default()
                    }
                    .into(),
                ],
                ..Default::default()
            }
            .into(),
            MenuItem::Separator,
            RadioGroup {
                selected: self.selected_option,
                select: Box::new(|this: &mut Self, current| {
                    this.selected_option = current;
                }),
                options: vec![
                    RadioItem {
                        label: "Option 0".into(),
                        ..Default::default()
                    },
                    RadioItem {
                        label: "Option 1".into(),
                        ..Default::default()
                    },
                    RadioItem {
                        label: "Option 2".into(),
                        ..Default::default()
                    },
                ],
                ..Default::default()
            }
            .into(),
            CheckmarkItem {
                label: "Checkable".into(),
                checked: self.checked,
                activate: Box::new(|this: &mut Self| this.checked = !this.checked),
                ..Default::default()
            }
            .into(),
            StandardItem {
                label: "Exit".into(),
                icon_name: "application-exit".into(),
                activate: Box::new(|_| std::process::exit(0)),
                ..Default::default()
            }
            .into(),
        ]
    }
}

fn main() {
    let service = ksni::TrayService::new(MyTray {
        selected_option: 0,
        checked: false,
    });
    let handle = service.handle();
    service.spawn();

    std::thread::sleep(std::time::Duration::from_secs(5));
    // We can modify the tray
    handle.update(|tray: &mut MyTray| {
        tray.checked = true;
    });
    // Run forever
    loop {
        std::thread::park();
    }
}

将创建类似这样的系统托盘

screenshot_of_example_in_gnome.png

(在带有 AppIndicator 扩展的 GNOME 中)

待办事项

  • org.kde.StatusNotifierItem
  • com.canonical.dbusmenu
  • org.freedesktop.DBus.Introspectable
  • org.freedesktop.DBus.Properties
  • 单选项目
  • 文档
  • 异步 diwic/dbus-rs#166
  • 可变菜单项

许可证

这是一款免费且不受限制的软件,已释放到公有领域。

任何人都可以免费复制、修改、发布、使用、编译、出售或分发此软件,无论是以源代码形式还是编译的二进制形式,用于任何目的,无论是商业用途还是非商业用途,以及通过任何手段。

依赖项

~6MB
~134K SLoC