From e7fde601505f3ebe360e81a7d82db685039b0c05 Mon Sep 17 00:00:00 2001 From: Frank Skare Date: Wed, 22 Apr 2020 05:52:11 +0200 Subject: [PATCH] full implementation for `window-minimized` and `window-maximized` --- Changelog.md | 7 +- Manual.md | 31 ++++-- mpv.net/Misc/App.cs | 1 - mpv.net/Native/Native.cs | 2 +- mpv.net/WinForms/MainForm.cs | 100 ++++++++++++------ mpv.net/mpv/mp.cs | 33 ++++++ .../examples/dynamic-context-menu-items.cs | 37 +++++++ scripts/examples/pause-when-minimize.lua | 19 ++++ 8 files changed, 184 insertions(+), 46 deletions(-) create mode 100644 scripts/examples/dynamic-context-menu-items.cs create mode 100644 scripts/examples/pause-when-minimize.lua diff --git a/Changelog.md b/Changelog.md index 0584df5..870c5e1 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,9 +2,10 @@ 5.4.4.4 Beta (not yet released) ============ -- with `border=no` the osc top bar window buttons min, max, close did not work. -- some anamorphic videos were shown with black bars -- crash fixed when PowerShell 5.1 is not available +- with `border=no` the OSC top bar window buttons min, max and close are supported. +- anamorphic videos are shown without black bars, the window is resized according to the ascpect ratio. +- PowerShell 5.1 was made optional. +- full implementation for `window-minimized` and `window-maximized` 5.4.4.3 Beta diff --git a/Manual.md b/Manual.md index 943301b..bb52fd9 100644 --- a/Manual.md +++ b/Manual.md @@ -102,8 +102,9 @@ Table of contents + [Exit](#exit) + [Exit Watch Later](#exit-watch-later) -About mpv.net -------------- + +Description +----------- mpv.net is a modern desktop media player for Windows. mpv is similar to VLC not based on DirectShow like MPC, mpv.net is based on libmpv which in return is based on ffmpeg. @@ -189,7 +190,8 @@ The config folder can be opened from the context menu. Command Line Interface ---------------------- -`mpvnet --mute=yes ` +mpvnet [options] [file|URL|PLAYLIST|-] +mpvnet [options] files mpv properties can be set with the same syntax as mpv, that is: @@ -352,17 +354,21 @@ Pressing the shift key while opening a single file will suppress loading all fil Differences ----------- -mpv.net was designed to work exactly like mpv, there are few limitations: +mpv.net is designed to work exactly like mpv, there are a few limitations: ### Window Limitations -mpv.net implements an own main window and because of that all window related features of mpv are not available unless mpv.net has an own implementation. Find the documentation of mpvs window related features here: +mpv.net implements an own main window which means only mpv window features are supported that have an own implementation in mpv.net. + +A window free mode is currently not supported. + +The documentation of mpvs window features can be found here: -mpv.net has currently implemented the following window related features: +mpv.net has currently implemented the following window features: [screen](https://mpv.io/manual/master/#options-screen) @@ -372,15 +378,18 @@ mpv.net has currently implemented the following window related features: [border](https://mpv.io/manual/master/#options-border) -[autofit](https://mpv.io/manual/master/#options-autofit) (only partly implemented) +[window-minimized](https://mpv.io/manual/master/#options-window-minimized) -[autofit-smaller](https://mpv.io/manual/master/#options-autofit-smaller) (only partly implemented) +[window-maximized](https://mpv.io/manual/master/#options-window-maximized) -[autofit-larger](https://mpv.io/manual/master/#options-autofit-larger) (only partly implemented) -[window-minimized](https://mpv.io/manual/master/#options-window-minimized) (only partly implemented, use Win+Up and Win+Down) +**Partly implemented are:** -[window-maximized](https://mpv.io/manual/master/#options-window-maximized) (only partly implemented, use Win+Up and Win+Down) +[autofit](https://mpv.io/manual/master/#options-autofit) + +[autofit-smaller](https://mpv.io/manual/master/#options-autofit-smaller) + +[autofit-larger](https://mpv.io/manual/master/#options-autofit-larger) ### Command Line Limitations diff --git a/mpv.net/Misc/App.cs b/mpv.net/Misc/App.cs index 2643473..f5ac4dc 100644 --- a/mpv.net/Misc/App.cs +++ b/mpv.net/Misc/App.cs @@ -8,7 +8,6 @@ using System.Windows.Forms; using UI; using static libmpv; -using static NewLine; using System.Threading.Tasks; diff --git a/mpv.net/Native/Native.cs b/mpv.net/Native/Native.cs index 1455b07..2f8982f 100644 --- a/mpv.net/Native/Native.cs +++ b/mpv.net/Native/Native.cs @@ -39,7 +39,7 @@ public class WinAPI public static extern bool AdjustWindowRect(ref RECT lpRect, uint dwStyle, bool bMenu); [DllImport("user32.dll")] - public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags); + public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags); [DllImport("user32.dll", EntryPoint = "GetWindowLong")] static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex); diff --git a/mpv.net/WinForms/MainForm.cs b/mpv.net/WinForms/MainForm.cs index 65dbf8e..c42e660 100644 --- a/mpv.net/WinForms/MainForm.cs +++ b/mpv.net/WinForms/MainForm.cs @@ -21,10 +21,11 @@ namespace mpvnet public static MainForm Instance { get; set; } public static IntPtr Hwnd { get; set; } public new ContextMenuStripEx ContextMenu { get; set; } - Point LastCursorPosChanged; - int LastCursorChangedTickCount; + Point LastCursorPosition; + int LastCursorChanged; int TaskbarButtonCreatedMessage; int ShownTickCount; + DateTime LastCycleFullscreen; Taskbar Taskbar; List RecentFiles; @@ -54,8 +55,8 @@ namespace mpvnet mp.Idle += Idle; mp.Seek += () => UpdateProgressBar(); - mp.observe_property_bool("window-maximized", PropChangeWindowMaximized); - mp.observe_property_bool("window-minimized", PropChangeWindowMinimized); + mp.observe_property("window-maximized", PropChangeWindowMaximized); + mp.observe_property("window-minimized", PropChangeWindowMinimized); mp.observe_property_bool("pause", PropChangePause); mp.observe_property_bool("fullscreen", PropChangeFullscreen); mp.observe_property_bool("ontop", PropChangeOnTop); @@ -112,6 +113,15 @@ namespace mpvnet SetFormPosAndSize(1, true); WindowState = FormWindowState.Maximized; } + + if (mp.WindowMinimized) + { + SetFormPosAndSize(1, true); + WindowState = FormWindowState.Minimized; + } + + if (!mp.Border) + FormBorderStyle = FormBorderStyle.None; } catch (Exception ex) { @@ -276,7 +286,7 @@ namespace mpvnet { if (!force) { - if (WindowState == FormWindowState.Maximized) + if (WindowState == FormWindowState.Maximized || WindowState == FormWindowState.Minimized) return; if (mp.Fullscreen) @@ -379,6 +389,14 @@ namespace mpvnet { FormBorderStyle = FormBorderStyle.None; WindowState = FormWindowState.Maximized; + + if (WasMaximized) + { + Rectangle b = Screen.FromControl(this).Bounds; + uint SWP_SHOWWINDOW = 0x0040; + IntPtr HWND_TOP= IntPtr.Zero; + WinAPI.SetWindowPos(Handle, HWND_TOP, b.X, b.Y, b.Width, b.Height, SWP_SHOWWINDOW); + } } } else @@ -466,6 +484,16 @@ namespace mpvnet RecentFiles.RemoveAt(App.RecentCount); } + void SaveWindowProperties() + { + if (WindowState == FormWindowState.Normal) + { + RegistryHelp.SetValue(App.RegPath, "PosX", Left + Width / 2); + RegistryHelp.SetValue(App.RegPath, "PosY", Top + Height / 2); + RegistryHelp.SetValue(App.RegPath, "Height", ClientSize.Height); + } + } + protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; @@ -503,7 +531,7 @@ namespace mpvnet mp.command($"mouse {pos.X} {pos.Y}"); } - if (CursorHelp.IsPosDifferent(LastCursorPosChanged)) + if (CursorHelp.IsPosDifferent(LastCursorPosition)) CursorHelp.Show(); } break; @@ -585,12 +613,12 @@ namespace mpvnet void CursorTimer_Tick(object sender, EventArgs e) { - if (CursorHelp.IsPosDifferent(LastCursorPosChanged)) + if (CursorHelp.IsPosDifferent(LastCursorPosition)) { - LastCursorPosChanged = Control.MousePosition; - LastCursorChangedTickCount = Environment.TickCount; + LastCursorPosition = Control.MousePosition; + LastCursorChanged = Environment.TickCount; } - else if (Environment.TickCount - LastCursorChangedTickCount > 1500 && + else if (Environment.TickCount - LastCursorChanged > 1500 && !IsMouseInOSC() && ClientRectangle.Contains(PointToClient(MousePosition)) && Form.ActiveForm == this && !ContextMenu.Visible) @@ -624,15 +652,15 @@ namespace mpvnet } } - void PropChangeWindowMaximized(bool enabled) + void PropChangeWindowMaximized() { if (!WasShown()) return; - mp.WindowMaximized = enabled; - BeginInvoke(new Action(() => { + mp.WindowMaximized = mp.get_property_bool("window-maximized"); + if (mp.WindowMaximized && WindowState != FormWindowState.Maximized) WindowState = FormWindowState.Maximized; else if (!mp.WindowMaximized && WindowState == FormWindowState.Maximized) @@ -640,16 +668,18 @@ namespace mpvnet })); } - void PropChangeWindowMinimized(bool enabled) + void PropChangeWindowMinimized() { if (!WasShown()) return; BeginInvoke(new Action(() => { - if (enabled && WindowState != FormWindowState.Minimized) + mp.WindowMinimized = mp.get_property_bool("window-minimized"); + + if (mp.WindowMinimized && WindowState != FormWindowState.Minimized) WindowState = FormWindowState.Minimized; - else if (!enabled && WindowState == FormWindowState.Minimized) + else if (!mp.WindowMinimized && WindowState == FormWindowState.Minimized) WindowState = FormWindowState.Normal; })); } @@ -729,10 +759,30 @@ namespace mpvnet if (mp.IsLogoVisible) mp.ShowLogo(); - if (WindowState == FormWindowState.Maximized && FormBorderStyle != FormBorderStyle.None) - WasMaximized = true; - else if (WindowState == FormWindowState.Normal && FormBorderStyle != FormBorderStyle.None) - WasMaximized = false; + if (FormBorderStyle != FormBorderStyle.None) + { + if (WindowState == FormWindowState.Maximized) + WasMaximized = true; + else if (WindowState == FormWindowState.Normal) + WasMaximized = false; + } + + if (WasShown()) + { + if (WindowState == FormWindowState.Minimized) + { + mp.set_property_string("window-minimized", "yes"); + } + else if (WindowState == FormWindowState.Normal) + { + mp.set_property_string("window-maximized", "no"); + mp.set_property_string("window-minimized", "no"); + } + else if (WindowState == FormWindowState.Maximized) + { + mp.set_property_string("window-maximized", "yes"); + } + } } protected override void OnFormClosing(FormClosingEventArgs e) @@ -756,16 +806,6 @@ namespace mpvnet } catch {} } - void SaveWindowProperties() - { - if (WindowState == FormWindowState.Normal) - { - RegistryHelp.SetValue(App.RegPath, "PosX", Left + Width / 2); - RegistryHelp.SetValue(App.RegPath, "PosY", Top + Height / 2); - RegistryHelp.SetValue(App.RegPath, "Height", ClientSize.Height); - } - } - protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); diff --git a/mpv.net/mpv/mp.cs b/mpv.net/mpv/mp.cs index 2e55aa3..c94b978 100644 --- a/mpv.net/mpv/mp.cs +++ b/mpv.net/mpv/mp.cs @@ -59,6 +59,7 @@ namespace mpvnet public static event Action Initialized; + public static List> PropChangeActions { get; set; } = new List>(); public static List>> BoolPropChangeActions { get; set; } = new List>>(); public static List>> IntPropChangeActions { get; set; } = new List>>(); public static List>> DoublePropChangeActions { get; set; } = new List>>(); @@ -87,6 +88,7 @@ namespace mpvnet public static bool IsQuitNeeded { set; get; } = true; public static bool TaskbarProgress { get; set; } = true; public static bool WindowMaximized { get; set; } + public static bool WindowMinimized { get; set; } public static int Screen { get; set; } = -1; public static int Edition { get; set; } @@ -153,6 +155,7 @@ namespace mpvnet case "fullscreen": Fullscreen = value == "yes"; break; case "border": Border = value == "yes"; break; case "window-maximized": WindowMaximized = value == "yes"; break; + case "window-minimized": WindowMinimized = value == "yes"; break; case "taskbar-progress": TaskbarProgress = value == "yes"; break; case "screen": Screen = Convert.ToInt32(value); break; case "gpu-api": GPUAPI = value; break; @@ -466,6 +469,13 @@ namespace mpvnet if (i.Key == data.name) i.Value.Invoke(Marshal.PtrToStructure(data.data)); } + else if (data.format == mpv_format.MPV_FORMAT_NONE) + { + lock (PropChangeActions) + foreach (var i in PropChangeActions) + if (i.Key == data.name) + i.Value.Invoke(); + } else if (data.format == mpv_format.MPV_FORMAT_DOUBLE) { lock (DoublePropChangeActions) @@ -598,6 +608,17 @@ namespace mpvnet return lpBuffer.ToInt32(); } + public static bool get_property_bool(string name, bool throwException = false) + { + mpv_error err = mpv_get_property(Handle, GetUtf8Bytes(name), + mpv_format.MPV_FORMAT_FLAG, out IntPtr lpBuffer); + + if (err < 0) + HandleError(err, throwException, $"error getting property: {name}"); + + return lpBuffer.ToInt32() != 0; + } + public static double get_property_number(string name, bool throwException = false) { mpv_error err = mpv_get_property(Handle, GetUtf8Bytes(name), @@ -666,6 +687,18 @@ namespace mpvnet StringPropChangeActions.Add(new KeyValuePair>(name, action)); } + public static void observe_property(string name, Action action) + { + mpv_error err = mpv_observe_property(Handle, (ulong)action.GetHashCode(), + name, mpv_format.MPV_FORMAT_NONE); + + if (err < 0) + HandleError(err, true, $"error observing property: {name}"); + else + lock (PropChangeActions) + PropChangeActions.Add(new KeyValuePair(name, action)); + } + public static void HandleError(mpv_error err, bool throwException, params string[] messages) { if (throwException) diff --git a/scripts/examples/dynamic-context-menu-items.cs b/scripts/examples/dynamic-context-menu-items.cs new file mode 100644 index 0000000..b8dae9d --- /dev/null +++ b/scripts/examples/dynamic-context-menu-items.cs @@ -0,0 +1,37 @@ + +// creates context menu items dynamically + +using mpvnet; +using System.ComponentModel; +using System.Linq; + +class Script +{ + MainForm MainForm; + + public Script() + { + MainForm = mpvnet.MainForm.Instance; + MainForm.ContextMenu.Opening += ContextMenu_Opening; + } + + void ContextMenu_Opening(object sender, CancelEventArgs e) + { + // edit input.conf and add 'Edition' menu item there + MenuItem menuItem = MainForm.FindMenuItem("Edition"); + + if (menuItem == null) + return; + + menuItem.DropDownItems.Clear(); + var editionTracks = mp.MediaTracks.Where(track => track.Type == "e"); + + foreach (MediaTrack track in editionTracks) + { + MenuItem mi = new MenuItem(track.Text); + mi.Action = () => { mp.commandv("set", "edition", track.ID.ToString()); }; + mi.Checked = mp.Edition == track.ID; + menuItem.DropDownItems.Add(mi); + } + } +} diff --git a/scripts/examples/pause-when-minimize.lua b/scripts/examples/pause-when-minimize.lua new file mode 100644 index 0000000..cda6b46 --- /dev/null +++ b/scripts/examples/pause-when-minimize.lua @@ -0,0 +1,19 @@ + +local did_minimize = false + +mp.observe_property("window-minimized", "bool", function(name, value) + local pause = mp.get_property_bool("pause") + + if value == true then + if pause == false then + mp.set_property_bool("pause", true) + did_minimize = true + end + elseif value == false then + if did_minimize and (pause == true) then + mp.set_property_bool("pause", false) + end + + did_minimize = false + end +end)