Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace libappindicator with ksni #201

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ serde = ["muda/serde", "dep:serde"]
common-controls-v6 = ["muda/common-controls-v6"]

[dependencies]
muda = { version = "0.14", default-features = false }
muda = { version = "0.15", default-features = false, features = ["ksni"] }
crossbeam-channel = "0.5"
once_cell = "1"
thiserror = "1.0"
Expand All @@ -32,7 +32,8 @@ features = [
]

[target."cfg(target_os = \"linux\")".dependencies]
libappindicator = "0.9"
arc-swap = "1.7.1"
ksni = "0.2.2"
dirs = "5"

[target."cfg(target_os = \"linux\")".dev-dependencies]
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ tray-icon lets you create tray icons for desktop applications.

## Dependencies (Linux Only)

On Linux, `gtk`, `libxdo` is used to make the predfined `Copy`, `Cut`, `Paste` and `SelectAll` menu items work and `libappindicator` or `libayatnat-appindicator` are used to create the tray icon, so make sure to install them on your system.
On Linux, `gtk`, `libxdo` is used to make the predfined `Copy`, `Cut`, `Paste` and `SelectAll` menu items work, so make sure to install them on your system.

#### Arch Linux / Manjaro:

```sh
pacman -S gtk3 xdotool libappindicator-gtk3 #or libayatana-appindicator
pacman -S gtk3 xdotool
```

#### Debian / Ubuntu:

```sh
sudo apt install libgtk-3-dev libxdo-dev libappindicator3-dev #or libayatana-appindicator3-dev
sudo apt install libgtk-3-dev libxdo-dev
```

## Examples
Expand Down
86 changes: 86 additions & 0 deletions examples/counter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2022-2022 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

#![allow(unused)]

use tao::event_loop::{ControlFlow, EventLoopBuilder};
use tray_icon::{
menu::{
AboutMetadata, CheckMenuItem, IconMenuItem, Menu, MenuEvent, MenuItem, PredefinedMenuItem,
Submenu,
},
TrayIconBuilder, TrayIconEvent,
};

fn main() {
let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png");

let event_loop = EventLoopBuilder::new().build();

let mut counter = 0;
let tray_menu = Menu::new();

let counter_i = MenuItem::new(format!("Counter: {counter}"), true, None);
tray_menu.append_items(&[&counter_i]);

let mut tray_icon = None;

let menu_channel = MenuEvent::receiver();
let tray_channel = TrayIconEvent::receiver();

event_loop.run(move |event, _, control_flow| {
// We add delay of 16 ms (60fps) to event_loop to reduce cpu load.
// Alternatively, you can set ControlFlow::Wait or use TrayIconEvent::set_event_handler,
// see https://github.com/tauri-apps/tray-icon/issues/83#issuecomment-1697773065
*control_flow = ControlFlow::Poll;
std::thread::sleep(std::time::Duration::from_millis(16));

if let tao::event::Event::NewEvents(tao::event::StartCause::Init) = event {
let icon = load_tray_icon(std::path::Path::new(path));

// We create the icon once the event loop is actually running
// to prevent issues like https://github.com/tauri-apps/tray-icon/issues/90
tray_icon = Some(
TrayIconBuilder::new()
.with_menu(Box::new(tray_menu.clone()))
.with_tooltip("tao - awesome windowing lib")
.with_icon(icon)
.build()
.unwrap(),
);

// We have to request a redraw here to have the icon actually show up.
// Tao only exposes a redraw method on the Window so we use core-foundation directly.
#[cfg(target_os = "macos")]
unsafe {
use core_foundation::runloop::{CFRunLoopGetMain, CFRunLoopWakeUp};

let rl = CFRunLoopGetMain();
CFRunLoopWakeUp(rl);
}
}

counter += 1;
counter_i.set_text(format!("Counter: {counter}"));
})
}

fn load_icon(path: &std::path::Path) -> (Vec<u8>, u32, u32) {
let image = image::open(path)
.expect("Failed to open icon path")
.into_rgba8();
let (width, height) = image.dimensions();
let rgba = image.into_raw();
(rgba, width, height)
}

fn load_tray_icon(path: &std::path::Path) -> tray_icon::Icon {
let (icon_rgba, icon_width, icon_height) = load_icon(path);
tray_icon::Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon")
}

fn load_menu_icon(path: &std::path::Path) -> muda::Icon {
let (icon_rgba, icon_width, icon_height) = load_icon(path);
muda::Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon")
}
51 changes: 36 additions & 15 deletions examples/tao.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@

use tao::event_loop::{ControlFlow, EventLoopBuilder};
use tray_icon::{
menu::{AboutMetadata, Menu, MenuEvent, MenuItem, PredefinedMenuItem},
menu::{
AboutMetadata, CheckMenuItem, IconMenuItem, Menu, MenuEvent, MenuItem, PredefinedMenuItem,
Submenu,
},
TrayIconBuilder, TrayIconEvent,
};

Expand All @@ -17,6 +20,16 @@ fn main() {

let tray_menu = Menu::new();

let icon_i = IconMenuItem::new(
"Icon",
true,
Some(load_menu_icon(std::path::Path::new(path))),
None,
);
let check_i = CheckMenuItem::new("Check", true, false, None);
let subitem_i = MenuItem::new("Subitem", true, None);
let submenu_i = Submenu::new("Submenu", true);
submenu_i.append(&subitem_i);
let quit_i = MenuItem::new("Quit", true, None);
tray_menu.append_items(&[
&PredefinedMenuItem::about(
Expand All @@ -28,6 +41,9 @@ fn main() {
}),
),
&PredefinedMenuItem::separator(),
&icon_i,
&check_i,
&submenu_i,
&quit_i,
]);

Expand All @@ -38,15 +54,13 @@ fn main() {

event_loop.run(move |event, _, control_flow| {
// We add delay of 16 ms (60fps) to event_loop to reduce cpu load.
// This can be removed to allow ControlFlow::Poll to poll on each cpu cycle
// Alternatively, you can set ControlFlow::Wait or use TrayIconEvent::set_event_handler,
// see https://github.com/tauri-apps/tray-icon/issues/83#issuecomment-1697773065
*control_flow = ControlFlow::WaitUntil(
std::time::Instant::now() + std::time::Duration::from_millis(16),
);
*control_flow = ControlFlow::Poll;
std::thread::sleep(std::time::Duration::from_millis(16));
Comment on lines +59 to +60
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any reason why this was changed to use thread sleep?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because otherwise the event loop won't wake up after the timeout, only when the user clicks the tray icon.

tauri-apps/tao#988


if let tao::event::Event::NewEvents(tao::event::StartCause::Init) = event {
let icon = load_icon(std::path::Path::new(path));
let icon = load_tray_icon(std::path::Path::new(path));

// We create the icon once the event loop is actually running
// to prevent issues like https://github.com/tauri-apps/tray-icon/issues/90
Expand Down Expand Up @@ -84,14 +98,21 @@ fn main() {
})
}

fn load_icon(path: &std::path::Path) -> tray_icon::Icon {
let (icon_rgba, icon_width, icon_height) = {
let image = image::open(path)
.expect("Failed to open icon path")
.into_rgba8();
let (width, height) = image.dimensions();
let rgba = image.into_raw();
(rgba, width, height)
};
fn load_icon(path: &std::path::Path) -> (Vec<u8>, u32, u32) {
let image = image::open(path)
.expect("Failed to open icon path")
.into_rgba8();
let (width, height) = image.dimensions();
let rgba = image.into_raw();
(rgba, width, height)
}

fn load_tray_icon(path: &std::path::Path) -> tray_icon::Icon {
let (icon_rgba, icon_width, icon_height) = load_icon(path);
tray_icon::Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon")
}

fn load_menu_icon(path: &std::path::Path) -> muda::Icon {
let (icon_rgba, icon_width, icon_height) = load_icon(path);
muda::Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon")
}
30 changes: 1 addition & 29 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,7 @@
//! }
//! ```

use std::{
cell::RefCell,
path::{Path, PathBuf},
rc::Rc,
};
use std::{cell::RefCell, rc::Rc};

use counter::Counter;
use crossbeam_channel::{unbounded, Receiver, Sender};
Expand Down Expand Up @@ -141,9 +137,6 @@ pub struct TrayIconAttributes {
/// Setting an empty [`Menu`](crate::menu::Menu) is enough.
pub icon: Option<Icon>,

/// Tray icon temp dir path. **Linux only**.
pub temp_dir_path: Option<PathBuf>,

/// Use the icon as a [template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc). **macOS only**.
pub icon_is_template: bool,

Expand All @@ -169,7 +162,6 @@ impl Default for TrayIconAttributes {
tooltip: None,
menu: None,
icon: None,
temp_dir_path: None,
icon_is_template: false,
menu_on_left_click: true,
title: None,
Expand Down Expand Up @@ -247,15 +239,6 @@ impl TrayIconBuilder {
self
}

/// Set tray icon temp dir path. **Linux only**.
///
/// On Linux, we need to write the icon to the disk and usually it will
/// be `$XDG_RUNTIME_DIR/tray-icon` or `$TEMP/tray-icon`.
pub fn with_temp_dir_path<P: AsRef<Path>>(mut self, s: P) -> Self {
self.attrs.temp_dir_path = Some(s.as_ref().to_path_buf());
self
}

/// Use the icon as a [template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc). **macOS only**.
pub fn with_icon_as_template(mut self, is_template: bool) -> Self {
self.attrs.icon_is_template = is_template;
Expand Down Expand Up @@ -368,17 +351,6 @@ impl TrayIcon {
self.tray.borrow_mut().set_visible(visible)
}

/// Sets the tray icon temp dir path. **Linux only**.
///
/// On Linux, we need to write the icon to the disk and usually it will
/// be `$XDG_RUNTIME_DIR/tray-icon` or `$TEMP/tray-icon`.
pub fn set_temp_dir_path<P: AsRef<Path>>(&self, path: Option<P>) {
#[cfg(target_os = "linux")]
self.tray.borrow_mut().set_temp_dir_path(path);
#[cfg(not(target_os = "linux"))]
let _ = path;
}

/// Set the current icon as a [template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc). **macOS only**.
pub fn set_icon_as_template(&self, is_template: bool) {
#[cfg(target_os = "macos")]
Expand Down
38 changes: 0 additions & 38 deletions src/platform_impl/gtk/icon.rs

This file was deleted.

Loading