Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions src/stremio_app/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use rand::Rng;
use serde_json;
use std::{
cell::RefCell,
cell::{Cell, RefCell},
io::Read,
os::windows::process::CommandExt,
path::{Path, PathBuf},
Expand Down Expand Up @@ -31,6 +31,7 @@

#[derive(Default, NwgUi)]
pub struct MainWindow {
pub pip_mode: Cell<bool>,
pub command: String,
pub commands_path: Option<String>,
pub webui_url: String,
Expand Down Expand Up @@ -63,6 +64,7 @@
(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)]
Expand All @@ -77,6 +79,9 @@
#[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]
Expand Down Expand Up @@ -243,6 +248,7 @@
}); // 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();
Expand All @@ -259,6 +265,7 @@
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();
Expand Down Expand Up @@ -353,6 +360,10 @@
}
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) {
Expand All @@ -372,6 +383,16 @@
}
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();
}
Expand Down Expand Up @@ -424,6 +445,6 @@
}
self.window.set_visible(false);
self.tray.tray_show_hide.set_checked(self.window.visible());
self.transmit_window_visibility_change();

Check warning on line 448 in src/stremio_app/app.rs

View workflow job for this annotation

GitHub Actions / test

Diff in \\?\D:\a\stremio-shell-ng\stremio-shell-ng\src\stremio_app\app.rs
}
}
}
58 changes: 30 additions & 28 deletions src/stremio_app/systray.rs
Original file line number Diff line number Diff line 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);
}
}
66 changes: 65 additions & 1 deletion src/stremio_app/window_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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