From ed38b4aa732d36d8f0a150d7537ee91b754d9b44 Mon Sep 17 00:00:00 2001 From: Nickiel12 <35903114+Nickiel12@users.noreply.github.com> Date: Wed, 13 Jul 2022 22:29:25 -0700 Subject: [PATCH] added demo tray_icon. has a bug where clicks get "stuck" in the queue --- Cargo.toml | 3 + src/icon1.ico | Bin 0 -> 34494 bytes src/icon2.ico | Bin 0 -> 34494 bytes src/main.rs | 11 +++- src/modules/mod.rs | 1 + src/modules/tray_icon.rs | 130 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 src/icon1.ico create mode 100644 src/icon2.ico create mode 100644 src/modules/tray_icon.rs diff --git a/Cargo.toml b/Cargo.toml index 8e68873..24ade03 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 = [] diff --git a/src/icon1.ico b/src/icon1.ico new file mode 100644 index 0000000000000000000000000000000000000000..31ff90f539017ea1bc8867c3f9f31bae023166aa GIT binary patch literal 34494 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 literal 0 HcmV?d00001 diff --git a/src/icon2.ico b/src/icon2.ico new file mode 100644 index 0000000000000000000000000000000000000000..9a356183c738c42e1c59668a93e37738c003b890 GIT binary patch literal 34494 zcmeI5J8vXK5XbvCjuR4x9e{KZb^yWxf=h{Poe&YEKmdsFczgj!ykw-joI#8Z5kiOv zcqG6V03<`iOUM$54-OCiU+wfV9_GC>v$N+KsjgquRsX84?&;|r&xLRAqm4NoUJL<>W!m7$_FIs8cc}k0(GQ{%kt&VIQ%4&-Ep?b|u+#rfQIwlcX@dve7CMZ7 zM}58%tGxYe%pF_nbL&bR6+#$Zd z7iD9KJax2nm|w`}G93f04|5IvuX~`%1BsTfLQ-s=gngr%VK)>}Y?p*$8Ir9?txAou=}Q-0F#GB&x>A5iTooX+B!+D?qqt!k~}0j5d9>&AyR`8 zdFp6`2i|Itja#FvWLGl36{(_<;DNU%3?>JgzNyih#RZ1c4~-2iU^LzAv+!$Hev>?X zme`{K$Mh3djBOL0Sswb(x4^EZRi>ZV&c<3+M^&Ca^lhrFfY0>5Dj8LJs@mvVAh&7N zB=oP^|HROb9maq@eZ(Jg=-m$b>9gegBTg&^+O9vWRXwaf3;p2O6|G?XJ%s_AM!x@` zKVCK#+50c^8)A-dPaf$08})nY9&iubN*>S|MD=yFktBx~ljO7WNisWEzY&24Ui#3t z=Hi@!--=!kEzT+KSHUm$fP26_;2v-fxCh(=?tvaXV9$}4^t||>=uy$tl*m&@TaWts z5M`Jp$lkkqR_S{p&KZ6a{hbnd>S%jT)ZiVxKCsovFzgqEM{i;#pNNh`s;ne<;H3|J z>y!-CZrJq(SMrjm>p3iakuea)GO>nTZ@DHfiiizWbRzm916gIt2BFle{uuE9NI@4sXHnj&?$V7HuU<>4!{JW%sb+9S6 zrhM;9CbA3k_Ely0xet9k0DkTd$nFblfgHony>yv1M?wn64w=X<(A!s);b%|qR|$qP zY)$HsiR`|>7Rb3J@UMIPto!^OYW-wQ9%KE~yja)!7gO5i@S5%);*w-Gtm*!3F$U~; z*L459uz_cfHGFV=`}b%X=9)Bx(D0??g96Jd%!*59$38x=C2WHr)Ad=DK9G_mzS4F zQ#uJ@pZv`bcC+bm2wRk6s@?Vm<*sRz6VtrDhyxu)5og4WV`v*DPm7A& z1qdhifyaQyfX9HxfX9HxfX9HxfX9HxfX9HxfX9HxKvfLr1VbkZtD`DxW3;ufo!@ky z5WOY(O7x2;{*FqXI@;h#{|>y~uVdI)r9)Wj#(z^huZw;ciMbKMOCS1H%CEvUMq3TO zXVlKvHnls?M_*)=`d|zjt8|oL@c#%N1%uwQ9&e_z%g#DMLQ#;~zUM`}NNwq+$6bh`ZtyD`?eG98S8 z=&Z;8=PQW+DXo8J{r%<()rI`bj&pXT~pfs;)j{2?LE9JKf28KW$W@- z^$~~Cv7Uc<#-8HyFXJ)B`3E{|>`BKO=Q2H6ENPzSlCE)G*Kg|QUyRFHKmUwAIIHL1 zi@B*-;H>iJCFTQtPn~zFoRvSt`F{$Z@Um9VL~Zs5{9Pq|7VEt7dAU|DTbIVFFT+(( zAAkRRQ*B?07~A8N$Wuof`#N|F?akMZWoMb5Jf5-3Ww^Y4^?L&!10MsA0gnNX0gnNX z0gnNX0gnNX0gnNX0gr(R#ekqp;^G4dTslJGvJWUI)e+Ga~fK i9b-Dv2M?$pDvf$#dYIzK {}, } + 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()); } - diff --git a/src/modules/mod.rs b/src/modules/mod.rs index bfe706d..fda7886 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -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; diff --git a/src/modules/tray_icon.rs b/src/modules/tray_icon.rs new file mode 100644 index 0000000..2b7d479 --- /dev/null +++ b/src/modules/tray_icon.rs @@ -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, + message_channel: crossbeam_channel::Receiver, +} + +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); + } + } + } + } + } + +} \ No newline at end of file