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"
|
serde_json = "1.0"
|
||||||
crossbeam-channel = "0.5"
|
crossbeam-channel = "0.5"
|
||||||
inputbot = {path = "D:\\Inputbot"}
|
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]
|
[features]
|
||||||
default = []
|
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;
|
use crate::modules::stream_states::state_update::StateUpdate;
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
use modules::tray_icon;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
mod modules;
|
mod modules;
|
||||||
|
@ -21,6 +24,10 @@ const SERVER_ADDRESS: &str = "10.0.0.209:5000";
|
||||||
const SERVER_ADDRESS: &str = "10.0.0.168:5000";
|
const SERVER_ADDRESS: &str = "10.0.0.168:5000";
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
||||||
|
let icon = include_bytes!("icon1.ico");
|
||||||
|
let mut tray_icon = tray_icon::TrayIcon::setup(icon);
|
||||||
|
|
||||||
let settings_json = load_json();
|
let settings_json = load_json();
|
||||||
let hotkeys = Hotkeys::new(settings_json);
|
let hotkeys = Hotkeys::new(settings_json);
|
||||||
|
|
||||||
|
@ -53,8 +60,11 @@ fn main() {
|
||||||
},
|
},
|
||||||
Err(_) => {},
|
Err(_) => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
let tick_update = state.tick();
|
let tick_update = state.tick();
|
||||||
handle_instructions(tick_update, &mut state, &socket, &hotkeys);
|
handle_instructions(tick_update, &mut state, &socket, &hotkeys);
|
||||||
|
|
||||||
|
tray_icon.process_tray_messages();
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("closing main thread");
|
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::Scene(state.current_scene).to_json().to_string());
|
||||||
socket.send(StateUpdate::PauseTimer(state.timer_paused_length.is_some()).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 message_handler;
|
||||||
pub mod socket_handler;
|
pub mod socket_handler;
|
||||||
pub mod external_interface;
|
pub mod external_interface;
|
||||||
|
pub mod tray_icon;
|
||||||
|
|
||||||
pub mod stream_states {
|
pub mod stream_states {
|
||||||
pub mod stream_state;
|
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