mirror of
https://github.com/Stremio/stremio-shell-ng.git
synced 2026-01-11 22:40:32 +00:00
Tray icon; win visibility WIP
This commit is contained in:
parent
e6cb1d8fa6
commit
381f6c4a8d
6 changed files with 125 additions and 11 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -500,6 +500,7 @@ dependencies = [
|
|||
name = "stremio-shell-ng"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"embed-resource",
|
||||
"mpv",
|
||||
"native-windows-derive",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ edition = "2018"
|
|||
|
||||
[dependencies]
|
||||
once_cell = "1.3.1"
|
||||
native-windows-gui = { version = "1.0.4", features = ["high-dpi", "notice"] }
|
||||
native-windows-gui = { version = "1.0.4", features = ["high-dpi", "notice", "tray-notification", "menu"] }
|
||||
native-windows-derive = "1.0.3"
|
||||
winapi = { version = "0.3.9", features = [
|
||||
"libloaderapi", "handleapi", "wincon", "winuser"
|
||||
|
|
@ -18,5 +18,6 @@ serde_json = "1.0"
|
|||
structopt = "0.3"
|
||||
open = "1"
|
||||
urlencoding = "2.1.0"
|
||||
bitflags = "1.2.1"
|
||||
[build-dependencies]
|
||||
embed-resource = "1.3"
|
||||
embed-resource = "1.3"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
use native_windows_gui::{self as nwg, NativeUi};
|
||||
use structopt::StructOpt;
|
||||
use winapi::um::wincon::GetConsoleWindow;
|
||||
|
|
|
|||
|
|
@ -5,17 +5,28 @@ use std::cell::RefCell;
|
|||
use std::cmp;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use winapi::shared::windef::HWND__;
|
||||
use winapi::um::winuser::{
|
||||
GetSystemMetrics, GetWindowLongA, SetWindowLongA, GWL_EXSTYLE, GWL_STYLE, SM_CXSCREEN,
|
||||
SM_CYSCREEN, WS_CAPTION, WS_EX_CLIENTEDGE, WS_EX_DLGMODALFRAME, WS_EX_STATICEDGE,
|
||||
WS_EX_WINDOWEDGE, WS_THICKFRAME,
|
||||
GetActiveWindow, GetSystemMetrics, GetWindowLongA, IsIconic, IsZoomed, SetWindowLongA,
|
||||
GWL_EXSTYLE, GWL_STYLE, SM_CXSCREEN, SM_CYSCREEN, WS_CAPTION, WS_EX_CLIENTEDGE,
|
||||
WS_EX_DLGMODALFRAME, WS_EX_STATICEDGE, WS_EX_WINDOWEDGE, WS_THICKFRAME,
|
||||
};
|
||||
|
||||
use crate::stremio_app::ipc::{RPCRequest, RPCResponse, RPCResponseData, RPCResponseDataTransport};
|
||||
use crate::stremio_app::stremio_player::Player;
|
||||
use crate::stremio_app::stremio_wevbiew::WebView;
|
||||
use crate::stremio_app::systray::SystemTray;
|
||||
|
||||
#[derive(Default)]
|
||||
bitflags! {
|
||||
struct WindowState: u8 {
|
||||
const MINIMIZED = 0x01;
|
||||
const MAXIMIZED = 0x02;
|
||||
const FULL_SCREEN = 0x04;
|
||||
const ACTIVE = 0x08;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct WindowStyle {
|
||||
pub full_screen: bool,
|
||||
pub pos: (i32, i32),
|
||||
|
|
@ -23,6 +34,34 @@ pub struct WindowStyle {
|
|||
pub style: i32,
|
||||
pub ex_style: i32,
|
||||
}
|
||||
|
||||
impl WindowStyle {
|
||||
pub fn get_window_state(self, hwnd: *mut HWND__) -> u32 {
|
||||
let mut visibility: WindowState = WindowState::empty();
|
||||
visibility |= if 0 != unsafe { IsIconic(hwnd) } {
|
||||
WindowState::MINIMIZED
|
||||
} else {
|
||||
WindowState::empty()
|
||||
};
|
||||
visibility |= if 0 != unsafe { IsZoomed(hwnd) } {
|
||||
WindowState::MAXIMIZED
|
||||
} else {
|
||||
WindowState::empty()
|
||||
};
|
||||
visibility |= if hwnd == unsafe { GetActiveWindow() } {
|
||||
WindowState::ACTIVE
|
||||
} else {
|
||||
WindowState::empty()
|
||||
};
|
||||
visibility |= if self.full_screen {
|
||||
WindowState::FULL_SCREEN
|
||||
} else {
|
||||
WindowState::empty()
|
||||
};
|
||||
visibility.bits() as u32
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, NwgUi)]
|
||||
pub struct MainWindow {
|
||||
pub webui_url: String,
|
||||
|
|
@ -32,9 +71,12 @@ pub struct MainWindow {
|
|||
#[nwg_resource(source_embed: Some(&data.embed), source_embed_str: Some("MAINICON"))]
|
||||
pub window_icon: nwg::Icon,
|
||||
#[nwg_control(icon: Some(&data.window_icon), title: "Stremio", flags: "MAIN_WINDOW|VISIBLE")]
|
||||
#[nwg_events( OnWindowClose: [Self::on_quit], OnInit: [Self::on_init], OnPaint: [Self::on_paint], OnMinMaxInfo: [Self::on_min_max(SELF, EVT_DATA)] )]
|
||||
#[nwg_events( OnWindowClose: [Self::on_quit(SELF, EVT_DATA)], OnInit: [Self::on_init], OnPaint: [Self::on_paint], OnMinMaxInfo: [Self::on_min_max(SELF, EVT_DATA)], OnWindowMaximize: [Self::on_maximize] )]
|
||||
pub window: nwg::Window,
|
||||
#[nwg_partial(parent: window)]
|
||||
#[nwg_events((tray_exit, OnMenuItemSelected): [Self::on_quit_notice], (tray_show_hide, OnMenuItemSelected): [Self::on_show_hide]) ]
|
||||
pub tray: SystemTray,
|
||||
#[nwg_partial(parent: window)]
|
||||
pub webview: WebView,
|
||||
#[nwg_partial(parent: window)]
|
||||
pub player: Player,
|
||||
|
|
@ -73,6 +115,8 @@ impl MainWindow {
|
|||
.set_size(dimensions.0 as u32, dimensions.1 as u32);
|
||||
self.window.set_position(x, y);
|
||||
|
||||
self.tray.tray_show_hide.set_checked(true);
|
||||
|
||||
let player_channel = self.player.channel.borrow();
|
||||
let (player_tx, player_rx) = player_channel
|
||||
.as_ref()
|
||||
|
|
@ -250,6 +294,8 @@ impl MainWindow {
|
|||
});
|
||||
saved_style.full_screen = true;
|
||||
}
|
||||
let visibility = saved_style.clone().get_window_state(hwnd);
|
||||
|
||||
let web_channel = self.webview.channel.borrow();
|
||||
let (web_tx, _) = web_channel
|
||||
.as_ref()
|
||||
|
|
@ -258,19 +304,52 @@ impl MainWindow {
|
|||
web_tx_app
|
||||
.send(RPCResponse::visibility_change(
|
||||
true,
|
||||
1,
|
||||
visibility,
|
||||
saved_style.full_screen,
|
||||
))
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
fn on_quit_notice(&self) {
|
||||
self.on_quit();
|
||||
nwg::stop_thread_dispatch();
|
||||
}
|
||||
fn on_hide_splash_notice(&self) {
|
||||
self.splash_frame.set_visible(false);
|
||||
}
|
||||
fn on_quit(&self) {
|
||||
nwg::stop_thread_dispatch();
|
||||
fn on_maximize(&self) {}
|
||||
fn on_show_hide(&self) {
|
||||
self.window.set_visible(!self.window.visible());
|
||||
self.tray.tray_show_hide.set_checked(self.window.visible());
|
||||
let web_channel = self.webview.channel.borrow();
|
||||
let (web_tx, _) = web_channel
|
||||
.as_ref()
|
||||
.expect("Cannont obtain communication channel for the Web UI");
|
||||
let web_tx_app = web_tx.clone();
|
||||
let saved_style = self.saved_window_style.borrow();
|
||||
web_tx_app
|
||||
.send(RPCResponse::visibility_change(
|
||||
self.window.visible(),
|
||||
1,
|
||||
saved_style.full_screen,
|
||||
))
|
||||
.ok();
|
||||
}
|
||||
fn on_quit(&self, data: &nwg::EventData) {
|
||||
if let Some(hwnd) = self.window.handle.hwnd() {
|
||||
if let nwg::EventData::OnWindowClose(data) = data {
|
||||
data.close(false);
|
||||
}
|
||||
self.window.set_visible(false);
|
||||
let web_channel = self.webview.channel.borrow();
|
||||
let (web_tx, _) = web_channel
|
||||
.as_ref()
|
||||
.expect("Cannont obtain communication channel for the Web UI");
|
||||
let web_tx_app = web_tx.clone();
|
||||
let saved_style = self.saved_window_style.borrow();
|
||||
let visibility = saved_style.clone().get_window_state(hwnd);
|
||||
web_tx_app
|
||||
.send(RPCResponse::visibility_change(false, visibility, false))
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,3 +8,6 @@ pub mod stremio_server;
|
|||
pub use stremio_server::StremioServer;
|
||||
pub mod ipc;
|
||||
pub use ipc::{Channel, RPCRequest, RPCResponse, RPCResponseData, RPCResponseDataTransport};
|
||||
pub mod systray;
|
||||
pub use systray::SystemTray;
|
||||
|
||||
|
|
|
|||
28
src/stremio_app/systray.rs
Normal file
28
src/stremio_app/systray.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
use native_windows_derive::NwgPartial;
|
||||
use native_windows_gui as nwg;
|
||||
|
||||
#[derive(Default, NwgPartial)]
|
||||
pub struct SystemTray {
|
||||
#[nwg_resource]
|
||||
pub embed: nwg::EmbedResource,
|
||||
#[nwg_resource(source_embed: Some(&data.embed), source_embed_str: Some("MAINICON"))]
|
||||
pub tray_icon: nwg::Icon,
|
||||
#[nwg_control(icon: Some(&data.tray_icon), tip: Some("Stremio"))]
|
||||
#[nwg_events(MousePressLeftUp: [Self::show_menu], OnContextMenu: [Self::show_menu])]
|
||||
pub tray: nwg::TrayNotification,
|
||||
#[nwg_control(popup: true)]
|
||||
pub tray_menu: nwg::Menu,
|
||||
#[nwg_control(parent: tray_menu, text: "&Show Window")]
|
||||
pub tray_show_hide: nwg::MenuItem,
|
||||
#[nwg_control(parent: tray_menu, text: "Always on &Top")]
|
||||
pub tray_topmost: nwg::MenuItem,
|
||||
#[nwg_control(parent: tray_menu, text: "E&xit")]
|
||||
pub tray_exit: nwg::MenuItem,
|
||||
}
|
||||
|
||||
impl SystemTray {
|
||||
fn show_menu(&self) {
|
||||
let (x, y) = nwg::GlobalCursor::position();
|
||||
self.tray_menu.popup(x, y);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue