mirror of
https://github.com/Stremio/stremio-shell-ng.git
synced 2026-05-06 03:29:04 +00:00
Merge fc98c4e3ec into bbbe882faf
This commit is contained in:
commit
5fa83fa493
3 changed files with 118 additions and 31 deletions
|
|
@ -3,7 +3,7 @@ use native_windows_gui as nwg;
|
|||
use rand::Rng;
|
||||
use serde_json;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
cell::{Cell, RefCell},
|
||||
io::Read,
|
||||
os::windows::process::CommandExt,
|
||||
path::{Path, PathBuf},
|
||||
|
|
@ -31,6 +31,7 @@ use super::stremio_server::StremioServer;
|
|||
|
||||
#[derive(Default, NwgUi)]
|
||||
pub struct MainWindow {
|
||||
pub pip_mode: Cell<bool>,
|
||||
pub command: String,
|
||||
pub commands_path: Option<String>,
|
||||
pub webui_url: String,
|
||||
|
|
@ -63,6 +64,7 @@ pub struct MainWindow {
|
|||
(tray_exit, OnMenuItemSelected): [nwg::stop_thread_dispatch()],
|
||||
(tray_show_hide, OnMenuItemSelected): [Self::on_show_hide],
|
||||
(tray_topmost, OnMenuItemSelected): [Self::on_toggle_topmost],
|
||||
(tray_pip, OnMenuItemSelected): [Self::on_toggle_pip_notice],
|
||||
)]
|
||||
pub tray: SystemTray,
|
||||
#[nwg_partial(parent: window)]
|
||||
|
|
@ -77,6 +79,9 @@ pub struct MainWindow {
|
|||
#[nwg_events(OnNotice: [Self::on_toggle_fullscreen_notice] )]
|
||||
pub toggle_fullscreen_notice: nwg::Notice,
|
||||
#[nwg_control]
|
||||
#[nwg_events(OnNotice: [Self::on_toggle_pip_notice] )]
|
||||
pub toggle_pip_notice: nwg::Notice,
|
||||
#[nwg_control]
|
||||
#[nwg_events(OnNotice: [nwg::stop_thread_dispatch()] )]
|
||||
pub quit_notice: nwg::Notice,
|
||||
#[nwg_control]
|
||||
|
|
@ -243,6 +248,7 @@ impl MainWindow {
|
|||
}); // thread
|
||||
|
||||
let toggle_fullscreen_sender = self.toggle_fullscreen_notice.sender();
|
||||
let toggle_pip_sender = self.toggle_pip_notice.sender();
|
||||
let quit_sender = self.quit_notice.sender();
|
||||
let hide_splash_sender = self.hide_splash_notice.sender();
|
||||
let focus_sender = self.focus_notice.sender();
|
||||
|
|
@ -259,6 +265,7 @@ impl MainWindow {
|
|||
web_tx_web.send(RPCResponse::get_handshake()).ok();
|
||||
}
|
||||
Some("win-set-visibility") => toggle_fullscreen_sender.notice(),
|
||||
Some("win-pip-toggle") => toggle_pip_sender.notice(),
|
||||
Some("quit") => quit_sender.notice(),
|
||||
Some("app-ready") => {
|
||||
hide_splash_sender.notice();
|
||||
|
|
@ -353,6 +360,10 @@ impl MainWindow {
|
|||
}
|
||||
fn on_min_max(&self, data: &nwg::EventData) {
|
||||
let data = data.on_min_max();
|
||||
if self.pip_mode.get() {
|
||||
data.set_min_size(320, 180);
|
||||
return;
|
||||
}
|
||||
data.set_min_size(WINDOW_MIN_WIDTH, WINDOW_MIN_HEIGHT);
|
||||
}
|
||||
fn on_paint(&self) {
|
||||
|
|
@ -372,6 +383,16 @@ impl MainWindow {
|
|||
}
|
||||
self.transmit_window_visibility_change();
|
||||
}
|
||||
fn on_toggle_pip_notice(&self) {
|
||||
if let Some(hwnd) = self.window.handle.hwnd() {
|
||||
if let Ok(mut saved_style) = self.saved_window_style.try_borrow_mut() {
|
||||
self.pip_mode.set(!saved_style.pip);
|
||||
saved_style.toggle_pip(hwnd);
|
||||
self.tray.tray_pip.set_checked(saved_style.pip);
|
||||
self.webview.fit_to_window(self.window.handle.hwnd());
|
||||
}
|
||||
}
|
||||
}
|
||||
fn on_hide_splash_notice(&self) {
|
||||
self.splash_screen.hide();
|
||||
}
|
||||
|
|
@ -426,4 +447,4 @@ impl MainWindow {
|
|||
self.tray.tray_show_hide.set_checked(self.window.visible());
|
||||
self.transmit_window_visibility_change();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +1,30 @@
|
|||
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(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: "&Quit")]
|
||||
pub tray_exit: nwg::MenuItem,
|
||||
}
|
||||
|
||||
impl SystemTray {
|
||||
fn show_menu(&self) {
|
||||
let (x, y) = nwg::GlobalCursor::position();
|
||||
self.tray_menu.popup(x, y);
|
||||
}
|
||||
}
|
||||
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(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: "&Picture in Picture")]
|
||||
pub tray_pip: nwg::MenuItem,
|
||||
#[nwg_control(parent: tray_menu, text: "&Quit")]
|
||||
pub tray_exit: nwg::MenuItem,
|
||||
}
|
||||
|
||||
impl SystemTray {
|
||||
fn show_menu(&self) {
|
||||
let (x, y) = nwg::GlobalCursor::position();
|
||||
self.tray_menu.popup(x, y);
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,9 @@ bitflags! {
|
|||
#[derive(Default, Clone)]
|
||||
pub struct WindowStyle {
|
||||
pub full_screen: bool,
|
||||
pub pip: bool,
|
||||
pub pip_pos: (i32, i32),
|
||||
pub pip_size: (i32, i32),
|
||||
pub pos: (i32, i32),
|
||||
pub size: (i32, i32),
|
||||
pub style: i32,
|
||||
|
|
@ -148,9 +151,70 @@ impl WindowStyle {
|
|||
}
|
||||
self.ex_style = unsafe { GetWindowLongA(hwnd, GWL_EXSTYLE) };
|
||||
}
|
||||
pub fn toggle_pip(&mut self, hwnd: HWND) {
|
||||
if self.pip {
|
||||
// Restore from PiP
|
||||
unsafe {
|
||||
SetWindowLongA(hwnd, GWL_STYLE, self.style);
|
||||
SetWindowLongA(hwnd, GWL_EXSTYLE, self.ex_style);
|
||||
}
|
||||
let topmost = if self.ex_style as u32 & WS_EX_TOPMOST == WS_EX_TOPMOST {
|
||||
HWND_TOPMOST
|
||||
} else {
|
||||
HWND_NOTOPMOST
|
||||
};
|
||||
self.show_window_at(hwnd, topmost);
|
||||
self.pip = false;
|
||||
} else {
|
||||
// Enter PiP — save current state
|
||||
unsafe {
|
||||
let mut rect = mem::zeroed();
|
||||
GetWindowRect(hwnd, &mut rect);
|
||||
self.pos = (rect.left, rect.top);
|
||||
self.size = ((rect.right - rect.left), (rect.bottom - rect.top));
|
||||
self.style = GetWindowLongA(hwnd, GWL_STYLE);
|
||||
self.ex_style = GetWindowLongA(hwnd, GWL_EXSTYLE);
|
||||
}
|
||||
|
||||
// Small window, no caption, keep thick frame for resize, always on top
|
||||
let pip_style = self.style & !(WS_THICKFRAME as i32);
|
||||
let pip_ex_style = self.ex_style
|
||||
& !(WS_EX_DLGMODALFRAME as i32
|
||||
| WS_EX_WINDOWEDGE as i32
|
||||
| WS_EX_CLIENTEDGE as i32
|
||||
| WS_EX_STATICEDGE as i32)
|
||||
| WS_EX_TOPMOST as i32;
|
||||
|
||||
unsafe {
|
||||
SetWindowLongA(hwnd, GWL_STYLE, pip_style);
|
||||
SetWindowLongA(hwnd, GWL_EXSTYLE, pip_ex_style);
|
||||
}
|
||||
|
||||
// Position bottom-right corner, 400x225 (16:9)
|
||||
let monitor_w = unsafe { GetSystemMetrics(SM_CXSCREEN) };
|
||||
let monitor_h = unsafe { GetSystemMetrics(SM_CYSCREEN) };
|
||||
let pip_w = 400;
|
||||
let pip_h = 225;
|
||||
let pip_x = monitor_w - pip_w - 20;
|
||||
let pip_y = monitor_h - pip_h - 60;
|
||||
|
||||
unsafe {
|
||||
SetWindowPos(
|
||||
hwnd,
|
||||
HWND_TOPMOST,
|
||||
pip_x,
|
||||
pip_y,
|
||||
pip_w,
|
||||
pip_h,
|
||||
SWP_FRAMECHANGED,
|
||||
);
|
||||
}
|
||||
self.pip = true;
|
||||
}
|
||||
}
|
||||
pub fn set_active(&mut self, hwnd: HWND) {
|
||||
unsafe {
|
||||
SetForegroundWindow(hwnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue