Skip to content

Commit

Permalink
docs: Clearify event loop requirements on macOS (#122)
Browse files Browse the repository at this point in the history
* docs: Clearify event loop requirements on macOS

* linux

* windows

* windows

* mv import

* tao example
  • Loading branch information
FabianLars authored Mar 28, 2024
1 parent 9f970dc commit 3b11249
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 21 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ cocoa = "0.25"
objc = "0.2"
core-graphics = "0.23.1"

[target."cfg(target_os = \"macos\")".dev-dependencies]
core-foundation = "0.9"

[target."cfg(any(target_os = \"linux\", target_os = \"macos\"))".dependencies]
png = "0.17"

Expand Down
37 changes: 27 additions & 10 deletions examples/tao.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use tray_icon::{

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

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

Expand All @@ -32,21 +31,39 @@ fn main() {
&quit_i,
]);

let mut tray_icon = Some(
TrayIconBuilder::new()
.with_menu(Box::new(tray_menu))
.with_tooltip("tao - awesome windowing lib")
.with_icon(icon)
.build()
.unwrap(),
);
let mut tray_icon = None;

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

event_loop.run(move |_event, _, control_flow| {
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Poll;

if let tao::event::Event::NewEvents(tao::event::StartCause::Init) = event {
let icon = load_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);
}
}

if let Ok(event) = menu_channel.try_recv() {
if event.id == quit_i.id() {
tray_icon.take();
Expand Down
40 changes: 30 additions & 10 deletions examples/winit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use winit::event_loop::{ControlFlow, EventLoopBuilder};

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

// Since winit doesn't use gtk on Linux, and we need gtk for
// the tray icon to show up, we need to spawn a thread
Expand All @@ -21,6 +20,8 @@ fn main() {
std::thread::spawn(|| {
use tray_icon::menu::Menu;

let icon = load_icon(std::path::Path::new(path));

gtk::init().unwrap();
let _tray_icon = TrayIconBuilder::new()
.with_menu(Box::new(Menu::new()))
Expand All @@ -34,21 +35,40 @@ fn main() {
let event_loop = EventLoopBuilder::new().build().unwrap();

#[cfg(not(target_os = "linux"))]
let mut tray_icon = Some(
TrayIconBuilder::new()
.with_menu(Box::new(Menu::new()))
.with_tooltip("winit - awesome windowing lib")
.with_icon(icon)
.build()
.unwrap(),
);
let mut tray_icon = None;

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

event_loop.run(move |_event, event_loop| {
event_loop.run(move |event, event_loop| {
event_loop.set_control_flow(ControlFlow::Poll);

#[cfg(not(target_os = "linux"))]
if let winit::event::Event::NewEvents(winit::event::StartCause::Init) = event {
let icon = load_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(Menu::new()))
.with_tooltip("winit - awesome windowing lib")
.with_icon(icon)
.with_title("x")
.build()
.unwrap(),
);
// We have to request a redraw here to have the icon actually show up.
// Winit 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);
}
}

if let Ok(event) = tray_channel.try_recv() {
println!("{event:?}");
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
//! # Platform-specific notes:
//!
//! - On Windows and Linux, an event loop must be running on the thread, on Windows, a win32 event loop and on Linux, a gtk event loop. It doesn't need to be the main thread but you have to create the tray icon on the same thread as the event loop.
//! - On macOS, an event loop must be running on the main thread so you also need to create the tray icon on the main thread.
//! - On macOS, an event loop must be running on the main thread so you also need to create the tray icon on the main thread. You must make sure that the event loop is already running and not just created before creating a TrayIcon to prevent issues with fullscreen apps. In Winit for example the earliest you can create icons is on [`StartCause::Init`](https://docs.rs/winit/latest/winit/event/enum.StartCause.html#variant.Init).
//!
//! # Dependencies (Linux Only)
//!
Expand Down

0 comments on commit 3b11249

Please sign in to comment.