added demo tray_icon. has a bug where clicks get "stuck" in the queue
This commit is contained in:
parent
cce730a57f
commit
ed38b4aa73
6 changed files with 144 additions and 1 deletions
|
@ -11,6 +11,9 @@ ctrlc = "3.2.1"
|
|||
serde_json = "1.0"
|
||||
crossbeam-channel = "0.5"
|
||||
inputbot = {path = "D:\\Inputbot"}
|
||||
winit = "0.25"
|
||||
winapi = { version = "0.3.9", features = ["winuser", "windef", "minwindef", "shellapi", "libloaderapi", "commctrl", "basetsd"] }
|
||||
trayicon = { version="0.1.3", features = ["crossbeam-channel"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
|
BIN
src/icon1.ico
Normal file
BIN
src/icon1.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
BIN
src/icon2.ico
Normal file
BIN
src/icon2.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
11
src/main.rs
11
src/main.rs
|
@ -6,6 +6,9 @@ use workctl::sync_flag;
|
|||
|
||||
use crate::modules::stream_states::state_update::StateUpdate;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
use modules::tray_icon;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod modules;
|
||||
|
@ -21,6 +24,10 @@ const SERVER_ADDRESS: &str = "10.0.0.209:5000";
|
|||
const SERVER_ADDRESS: &str = "10.0.0.168:5000";
|
||||
|
||||
fn main() {
|
||||
|
||||
let icon = include_bytes!("icon1.ico");
|
||||
let mut tray_icon = tray_icon::TrayIcon::setup(icon);
|
||||
|
||||
let settings_json = load_json();
|
||||
let hotkeys = Hotkeys::new(settings_json);
|
||||
|
||||
|
@ -53,8 +60,11 @@ fn main() {
|
|||
},
|
||||
Err(_) => {},
|
||||
}
|
||||
|
||||
let tick_update = state.tick();
|
||||
handle_instructions(tick_update, &mut state, &socket, &hotkeys);
|
||||
|
||||
tray_icon.process_tray_messages();
|
||||
}
|
||||
|
||||
println!("closing main thread");
|
||||
|
@ -109,4 +119,3 @@ fn update_all(state: &StreamState, socket: &Socket) {
|
|||
socket.send(StateUpdate::Scene(state.current_scene).to_json().to_string());
|
||||
socket.send(StateUpdate::PauseTimer(state.timer_paused_length.is_some()).to_json().to_string());
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
pub mod message_handler;
|
||||
pub mod socket_handler;
|
||||
pub mod external_interface;
|
||||
pub mod tray_icon;
|
||||
|
||||
pub mod stream_states {
|
||||
pub mod stream_state;
|
||||
|
|
130
src/modules/tray_icon.rs
Normal file
130
src/modules/tray_icon.rs
Normal file
|
@ -0,0 +1,130 @@
|
|||
use core::mem::MaybeUninit;
|
||||
use std::time::Duration;
|
||||
use trayicon::*;
|
||||
use winapi::um::winuser;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum Events {
|
||||
ClickTrayIcon,
|
||||
DoubleClickTrayIcon,
|
||||
Exit,
|
||||
Item1,
|
||||
Item2,
|
||||
Item3,
|
||||
Item4,
|
||||
CheckItem1,
|
||||
SubItem1,
|
||||
SubItem2,
|
||||
SubItem3,
|
||||
}
|
||||
|
||||
pub struct TrayIcon {
|
||||
tray_icon: trayicon::TrayIcon<Events>,
|
||||
message_channel: crossbeam_channel::Receiver<Events>,
|
||||
}
|
||||
|
||||
impl TrayIcon {
|
||||
|
||||
pub fn setup(icon: &[u8]) -> TrayIcon {
|
||||
|
||||
let (s, r) = crossbeam_channel::unbounded();
|
||||
let icon1 = include_bytes!("./../icon1.ico");
|
||||
let icon2 = include_bytes!("./../icon2.ico");
|
||||
|
||||
let second_icon = Icon::from_buffer(icon2, None, None).unwrap();
|
||||
let first_icon = Icon::from_buffer(icon1, None, None).unwrap();
|
||||
|
||||
// Needlessly complicated tray icon with all the whistles and bells
|
||||
let mut tray_icon = TrayIconBuilder::new()
|
||||
.sender_crossbeam(s)
|
||||
.icon_from_buffer(icon1)
|
||||
.tooltip("Cool Tray 👀 Icon")
|
||||
.on_click(Events::ClickTrayIcon)
|
||||
.on_double_click(Events::DoubleClickTrayIcon)
|
||||
.menu(
|
||||
MenuBuilder::new()
|
||||
.item("Item 3 Replace Menu 👍", Events::Item3)
|
||||
.item("Item 2 Change Icon Green", Events::Item2)
|
||||
.item("Item 1 Change Icon Red", Events::Item1)
|
||||
.separator()
|
||||
.checkable("This is checkable", true, Events::CheckItem1)
|
||||
.submenu(
|
||||
"Sub Menu",
|
||||
MenuBuilder::new()
|
||||
.item("Sub item 1", Events::SubItem1)
|
||||
.item("Sub Item 2", Events::SubItem2)
|
||||
.item("Sub Item 3", Events::SubItem3),
|
||||
)
|
||||
.with(MenuItem::Item {
|
||||
name: "Item Disabled".into(),
|
||||
disabled: true, // Disabled entry example
|
||||
id: Events::Item4,
|
||||
icon: None,
|
||||
})
|
||||
.separator()
|
||||
.item("E&xit", Events::Exit),
|
||||
)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
TrayIcon {
|
||||
tray_icon,
|
||||
message_channel: r,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_tray_messages(&self) {
|
||||
unsafe {
|
||||
let mut msg = MaybeUninit::uninit();
|
||||
let bret = winuser::PeekMessageW(msg.as_mut_ptr(), 0 as _, 0, 0, 1);
|
||||
|
||||
if bret > 0 {
|
||||
winuser::TranslateMessage(msg.as_ptr());
|
||||
winuser::DispatchMessageA(msg.as_ptr());
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let message = self.message_channel.recv_timeout(Duration::from_millis(10));
|
||||
match message {
|
||||
Err(_) => return,
|
||||
Ok(message) => {
|
||||
match message {
|
||||
Events::DoubleClickTrayIcon => {
|
||||
println!("Double click");
|
||||
}
|
||||
Events::ClickTrayIcon => {
|
||||
println!("Single click");
|
||||
}
|
||||
Events::Exit => {
|
||||
println!("Please exit");
|
||||
todo!()
|
||||
}
|
||||
Events::Item1 => {
|
||||
println!("item1");
|
||||
//tray_icon.set_icon(&second_icon).unwrap();
|
||||
}
|
||||
Events::Item2 => {
|
||||
println!("item2");
|
||||
//tray_icon.set_icon(&first_icon).unwrap();
|
||||
}
|
||||
Events::Item3 => {
|
||||
println!("item3");
|
||||
/*tray_icon
|
||||
.set_menu(
|
||||
&MenuBuilder::new()
|
||||
.item("New menu item", Events::Item1)
|
||||
.item("Exit", Events::Exit),
|
||||
)
|
||||
.unwrap();*/
|
||||
}
|
||||
e => {
|
||||
println!("{:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue