Skip to content
This repository has been archived by the owner on Dec 30, 2020. It is now read-only.

Commit

Permalink
Add basic tray icon implementation for Mac OS
Browse files Browse the repository at this point in the history
  • Loading branch information
daniel-abramov committed Aug 1, 2017
1 parent 3a013db commit 4d7e0c6
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 24 deletions.
23 changes: 12 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,21 @@ readme = "README.md"
keywords = ["gui"]

[dependencies]
libc="0.2"
log="0.3"

[target.'cfg(target_os = "windows")'.dependencies]
winapi="0.2"
user32-sys="0.2"
kernel32-sys="0.2"
libc="0.2"
winapi = "0.2"
user32-sys = "0.2"
kernel32-sys = "0.2"
shell32-sys = "0.1"

[target.'cfg(target_os = "linux")'.dependencies]
gtk="^0.1.2"
glib="^0.1.2"
libappindicator="0.2"
gtk = "^0.1.2"
glib = "^0.1.2"
libappindicator = "0.2"

# [target.'cfg(target_os = "macos")'.dependencies]
# objc="*"
# cocoa="*"
# core-foundation="*"
[target.'cfg(target_os = "macos")'.dependencies]
objc = "0.2"
cocoa = "0.9"
core-foundation = "0.4"
Binary file added examples/rust-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 13 additions & 5 deletions examples/systray-example.rs → examples/trayicon.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
extern crate systray;

//#[cfg(target_os = "windows")]
#[cfg(target_os = "windows")]
fn main() {
let mut app;
match systray::Application::new() {
Expand All @@ -27,7 +27,15 @@ fn main() {
app.wait_for_message();
}

// #[cfg(not(target_os = "windows"))]
// fn main() {
// panic!("Not implemented on this platform!");
// }
#[cfg(target_os = "macos")]
fn main() {
let mut app;
match systray::Application::new() {
Ok(w) => app = w,
Err(_) => panic!("Can't create tray icon app!")
}

const ICON_BUFFER: &'static [u8] = include_bytes!("rust-logo.png");
app.set_icon_from_buffer(ICON_BUFFER, 256, 256).unwrap();
app.wait_for_message();
}
98 changes: 90 additions & 8 deletions src/api/cocoa/mod.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,110 @@
//! Contains the implementation of the Mac OS X tray icon in the top bar.

use std;
use {SystrayError};

use cocoa::appkit::{NSApp, NSApplication, NSButton, NSImage, NSStatusBar, NSStatusItem,
NSSquareStatusItemLength};
use cocoa::base::{id, nil};
use cocoa::foundation::{NSData, NSSize, NSAutoreleasePool};
use libc::c_void;

use {SystrayEvent, SystrayError};

/// The generation representation of the Mac OS X application.
pub struct Window {
/// A mutable reference to the `NSApplication` instance of the currently running application.
application: id,
/// It seems that we have to use `NSAutoreleasePool` to prevent memory leaks.
autorelease_pool: id,
}

impl Window {
pub fn new() -> Result<Window, SystrayError> {
Err(SystrayError::NotImplementedError)
/// Creates a new instance of the `Window`.
pub fn new(_: std::sync::mpsc::Sender<SystrayEvent>) -> Result<Window, SystrayError> {
Ok(Window {
application: unsafe { NSApp() },
autorelease_pool: unsafe { NSAutoreleasePool::new(nil) },
})
}

/// Closes the current application.
pub fn quit(&self) {
unsafe { msg_send![self.application, terminate] };
}

pub fn shutdown(&self) -> Result<(), SystrayError> {
unimplemented!()
}

/// Sets the tooltip (not available for this platfor).
pub fn set_tooltip(&self, _: &String) -> Result<(), SystrayError> {
Err(SystrayError::OsError("This operating system does not support tooltips for the tray \
items".to_owned()))
}

/// Adds an additional item to the tray icon menu.
pub fn add_menu_entry(&self, _: u32, _: &String) -> Result<u32, SystrayError> {
unimplemented!()
}
pub fn add_menu_item<F>(&self, _: &String, _: F) -> Result<u32, SystrayError>
where F: std::ops::Fn(&Window) -> () + 'static
{

pub fn add_menu_separator(&self, _: u32) -> Result<(), SystrayError> {
unimplemented!()
}
pub fn wait_for_message(&mut self) {

/// Sets the application icon displayed in the tray bar. Accepts a `buffer` to the underlying
/// image, you can pass even encoded PNG images here. Supports the same list of formats as
/// `NSImage`.
pub fn set_icon_from_buffer(&mut self, buffer: &[u8], _: u32, _: u32)
-> Result<(), SystrayError>
{
const ICON_WIDTH: f64 = 18.0;
const ICON_HEIGHT: f64 = 18.0;

let tray_entry = unsafe {
NSStatusBar::systemStatusBar(nil).statusItemWithLength_(NSSquareStatusItemLength)
};

let nsdata = unsafe {
NSData::dataWithBytes_length_(nil,
buffer.as_ptr() as *const c_void,
buffer.len() as u64).autorelease()
};
if nsdata == nil {
return Err(SystrayError::OsError("Could not create `NSData` out of the passed buffer"
.to_owned()));
}

let nsimage = unsafe { NSImage::initWithData_(NSImage::alloc(nil), nsdata).autorelease() };
if nsimage == nil {
return Err(SystrayError::OsError("Could not create `NSImage` out of the created \
`NSData` buffer".to_owned()));
}

unsafe {
let new_size = NSSize::new(ICON_WIDTH, ICON_HEIGHT);
msg_send![nsimage, setSize:new_size];
tray_entry.button().setImage_(nsimage);
}

Ok(())
}

pub fn set_icon_from_file(&self, _: &String) -> Result<(), SystrayError> {
unimplemented!()
}
pub fn set_icon_from_buffer(&self, _: &[u8], _: u32, _: u32) -> Result<(), SystrayError> {

pub fn set_icon_from_resource(&self, _: &String) -> Result<(), SystrayError> {
unimplemented!()
}

/// Starts the application event loop. Calling this function will block the current thread.
pub fn wait_for_message(&mut self) {
unsafe { self.application.run() };
}
}

impl Drop for Window {
fn drop(&mut self) {
unsafe { self.autorelease_pool.drain() };
}
}
8 changes: 8 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ extern crate kernel32;
#[cfg(target_os = "windows")]
extern crate user32;
#[cfg(target_os = "windows")]
extern crate shell32;

#[cfg(target_os = "macos")]
extern crate cocoa;
#[cfg(target_os = "macos")]
#[macro_use]
extern crate objc;

extern crate libc;
#[cfg(target_os = "linux")]
extern crate gtk;
Expand Down

0 comments on commit 4d7e0c6

Please sign in to comment.