2

Is there a way to get the current position and size of the MPV media player's window (or an event that fires when they are changed)?


I'm trying to make a script that automatically saves the last position of the window, and then loads it when the player starts. Settings the position on startup can be done with geometry, but reading can't.

In the log it is logged when the windows is moved:

[  34.308][d][vo/gpu/win32] move window: 1953:48

And resized:

[  37.990][v][vo/gpu] Resize: 1810x1004
[  37.990][v][vo/gpu] Window size: 1810x1004

Is there a way to get these values or callbacks in a (javascript) script? I couldn't find the event in the documentation sadly, or did I just miss it?

Only thing I could find were dwidth and dheight, but these represent only the size of the video, not the entire window nor the position of it.

Thanks!

Note: I also asked this on mpv's github, but no reply yet. I'll update the other when I get a reply in either.

The Oddler
  • 6,314
  • 7
  • 51
  • 94

1 Answers1

2

I figured out a way using mp.utils.subprocess to run some powershell script, as mpv doesn't have any API's to get the position directly. It's a bit slow, but it does work:

(The ps1 script:)

Add-Type @"
using System;
using System.Runtime.InteropServices;
public class Window {
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
}
public struct RECT
{
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;
}
"@

$Handle = (Get-Process -Id $Args[0]).MainWindowHandle
$WindowRect = New-Object RECT
$GotWindowRect = [Window]::GetWindowRect($Handle, [ref]$WindowRect)
ConvertTo-Json($WindowRect)

This then gives you a json object that has the position and size of the window. You can then use SetWindowRect in a similar way to set the position again. Note that this rect doesn't correspond to the thing you would set with geometry in mpv itself, as this rect also includes the title bar and such.

Edit:

I made a better version.

The powershell script now gets the client-rect which can be used with geometry, and thus opening mpv is now much smoother.

So the new powershell script:

Add-Type @"
using System;
using System.Runtime.InteropServices;
public class Window {
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool ClientToScreen(IntPtr hWnd, ref POINT lpPoint);
}
public struct RECT
{
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;
}
public struct POINT
{
    public int x;
    public int y;
}
"@

$Handle = (Get-Process -Id $Args[0]).MainWindowHandle
$WindowRect = New-Object RECT
$ClientRect = New-Object RECT
$TopLeft = New-Object POINT
$BottomRight = New-Object POINT

[Window]::GetClientRect($Handle, [ref]$ClientRect) | out-null
$TopLeft.x = $ClientRect.Left
$TopLeft.y = $ClientRect.Top
$BottomRight.x = $ClientRect.Right
$BottomRight.y = $ClientRect.Bottom

[Window]::ClientToScreen($Handle, [ref]$TopLeft) | out-null
[Window]::ClientToScreen($Handle, [ref]$BottomRight) | out-null

$WindowRect.Left = $TopLeft.x
$WindowRect.Top = $TopLeft.y
$WindowRect.Right = $BottomRight.x
$WindowRect.Bottom = $BottomRight.y

ConvertTo-Json($WindowRect)

Then I have a javascript plugin that calls this ps1 in a simple javascript plugin:

// Some setup used by both reading and writing
var dir = mp.utils.split_path(mp.get_script_file())[0]
var rect_path = mp.utils.join_path(dir, "last_window_rect.txt")

// Read last window rect if present
try {
    var rect_json = mp.utils.read_file(rect_path)
    var rect = JSON.parse(rect_json)

    var width = rect.Right - rect.Left
    var height = rect.Bottom - rect.Top
    mp.set_property("screen", 0)
    mp.set_property("geometry", width + "x" + height + "+" + rect.Left + "+" + rect.Top)
}
catch (e) {
    dump(e)
}

// Save the rect at shutdown
function save_rect() {
    var ps1_script = mp.utils.join_path(dir, "Get-Client-Rect.ps1")
    var rect_json = mp.utils.subprocess({ args: ["powershell", "&(\"" + ps1_script + "\")", mp.utils.getpid()], cancellable: false }).stdout
    mp.utils.write_file("file://" + rect_path, rect_json)
}
mp.register_event("shutdown", save_rect)

You can also find these scripts on my github: https://github.com/TheOddler/mpv-config/tree/master/scripts but I can't promise these will stay the same forever.

The Oddler
  • 6,314
  • 7
  • 51
  • 94
  • Were you able to find a window move/resize event? – Phani Rithvij Mar 24 '20 at 14:06
  • 1
    This was a while ago, but I think I just saved the position once when closing mpv, and loaded it when opening it. So I don't use move/resize events. Though check the documentation for `[Window]::GetClientRect` stuff, there might be something you can use there. – The Oddler Mar 24 '20 at 14:26
  • I need this feature in Ubuntu. – kenn May 18 '21 at 12:49