Skip to content
This repository was archived by the owner on Dec 30, 2020. It is now read-only.
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
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.2"
glib = "0.3.1"
libappindicator = "0.3"

# [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.
20 changes: 13 additions & 7 deletions examples/systray-example.rs → examples/trayicon.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
extern crate systray;

//#[cfg(target_os = "windows")]
#[cfg(not(target_os = "windows"))]
fn main() {
let mut app;
match systray::Application::new() {
Ok(w) => app = w,
Err(_) => panic!("Can't create window!")
}
// w.set_icon_from_file(&"C:\\Users\\qdot\\code\\git-projects\\systray-rs\\resources\\rust.ico".to_string());
// w.set_tooltip(&"Whatever".to_string());
app.set_icon_from_file(&"/usr/share/gxkb/flags/ua.png".to_string()).ok();
app.add_menu_item(&"Print a thing".to_string(), |_| {
println!("Printing a thing!");
Expand All @@ -27,7 +25,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() };
}
}
4 changes: 4 additions & 0 deletions src/api/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,10 @@ impl Window {
panic!("Not implemented on this platform!");
}

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

pub fn quit(&self) {
glib::idle_add(|| {
gtk::main_quit();
Expand Down
14 changes: 14 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 Expand Up @@ -102,6 +110,12 @@ impl Application {
self.window.set_icon_from_resource(resource)
}

pub fn set_icon_from_buffer(&mut self, buffer: &[u8], width: u32, height: u32)
-> Result<(), SystrayError>
{
self.window.set_icon_from_buffer(buffer, width, height)
}

pub fn shutdown(&self) -> Result<(), SystrayError> {
self.window.shutdown()
}
Expand Down