High DPI multi monitor fix

This commit is contained in:
Frank Skare
2021-05-13 11:53:36 +02:00
parent 69857e0548
commit 8df330b7aa
9 changed files with 142 additions and 84 deletions

View File

@@ -4,11 +4,14 @@
- There is an issue with the `window-scale` mpv property, it does not - There is an issue with the `window-scale` mpv property, it does not
work correctly in mpv either, so I've removed support for it and work correctly in mpv either, so I've removed support for it and
added an own implementation `script-message mpv.net window-scale`. added my own implementation `script-message mpv.net window-scale`.
- The previous Beta replaced the CS-Script library with my own - The previous Beta replaced the CS-Script library with my own
C# scripting implementation. C# scripting implementation.
- If a player window border is near to a screen border and the window size - If a player window border is near to a screen border and the window size
changes, the player windows sticks to that near screen border location. changes, the player windows sticks to that near screen border location.
Furthermore the `remember-position` option remembers a near screen border
position instead of remembering the window center position.
- High DPI multi monitor fix.
- `start-size` option has new options, see in config editor and manual. - `start-size` option has new options, see in config editor and manual.

View File

@@ -167,6 +167,11 @@ namespace mpvnet
{ {
public static string ApplicationKey { get; } = @"HKCU\Software\" + Application.ProductName; public static string ApplicationKey { get; } = @"HKCU\Software\" + Application.ProductName;
public static void SetInt(string name, object value)
{
SetValue(ApplicationKey, name, value);
}
public static void SetValue(string path, string name, object value) public static void SetValue(string path, string name, object value)
{ {
using (RegistryKey regKey = GetRootKey(path).CreateSubKey(path.Substring(5), RegistryKeyPermissionCheck.ReadWriteSubTree)) using (RegistryKey regKey = GetRootKey(path).CreateSubKey(path.Substring(5), RegistryKeyPermissionCheck.ReadWriteSubTree))

View File

@@ -21,7 +21,7 @@ namespace mpvnet
Application.SetCompatibleTextRenderingDefault(false); Application.SetCompatibleTextRenderingDefault(false);
if (App.IsStartedFromTerminal) if (App.IsStartedFromTerminal)
WinAPI.AttachConsole(-1 /*ATTACH_PARENT_PROCESS*/); Native.AttachConsole(-1 /*ATTACH_PARENT_PROCESS*/);
if (core.ConfigFolder == "") if (core.ConfigFolder == "")
return; return;
@@ -73,15 +73,15 @@ namespace mpvnet
{ {
if (proc.MainWindowHandle != IntPtr.Zero) if (proc.MainWindowHandle != IntPtr.Zero)
{ {
WinAPI.AllowSetForegroundWindow(proc.Id); Native.AllowSetForegroundWindow(proc.Id);
var data = new WinAPI.COPYDATASTRUCT(); var data = new Native.COPYDATASTRUCT();
data.lpData = string.Join("\n", args2.ToArray()); data.lpData = string.Join("\n", args2.ToArray());
data.cbData = data.lpData.Length * 2 + 1; data.cbData = data.lpData.Length * 2 + 1;
WinAPI.SendMessage(proc.MainWindowHandle, 0x004A /*WM_COPYDATA*/, IntPtr.Zero, ref data); Native.SendMessage(proc.MainWindowHandle, 0x004A /*WM_COPYDATA*/, IntPtr.Zero, ref data);
mutex.Dispose(); mutex.Dispose();
if (App.IsStartedFromTerminal) if (App.IsStartedFromTerminal)
WinAPI.FreeConsole(); Native.FreeConsole();
return; return;
} }
@@ -97,7 +97,7 @@ namespace mpvnet
Application.Run(new MainForm()); Application.Run(new MainForm());
if (App.IsStartedFromTerminal) if (App.IsStartedFromTerminal)
WinAPI.FreeConsole(); Native.FreeConsole();
mutex.Dispose(); mutex.Dispose();
} }

View File

@@ -3,8 +3,10 @@ using System;
using System.Drawing; using System.Drawing;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
public class WinAPI public class Native
{ {
static Version Windows_10_1607 = new Version(10, 0, 14393); // Windows 10 1607
[DllImport("kernel32.dll")] [DllImport("kernel32.dll")]
public static extern bool AttachConsole(int dwProcessId); public static extern bool AttachConsole(int dwProcessId);
@@ -36,9 +38,16 @@ public class WinAPI
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern void ReleaseCapture(); public static extern void ReleaseCapture();
[DllImport("user32.dll")]
public static extern int GetDpiForWindow(IntPtr hwnd);
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern bool AdjustWindowRect(ref RECT lpRect, uint dwStyle, bool bMenu); public static extern bool AdjustWindowRect(ref RECT lpRect, uint dwStyle, bool bMenu);
[DllImport("user32.dll")]
public static extern bool AdjustWindowRectExForDpi(
ref RECT lpRect, uint dwStyle, bool bMenu, uint dwExStyle, uint dpi);
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags); public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
@@ -97,4 +106,50 @@ public class WinAPI
[MarshalAs(UnmanagedType.LPTStr)] [MarshalAs(UnmanagedType.LPTStr)]
public string lpData; public string lpData;
} }
public static int GetResizeBorder(int v)
{
switch (v)
{
case 1 /* WMSZ_LEFT */ : return 3;
case 3 /* WMSZ_TOP */ : return 2;
case 2 /* WMSZ_RIGHT */ : return 3;
case 6 /* WMSZ_BOTTOM */ : return 2;
case 4 /* WMSZ_TOPLEFT */ : return 1;
case 5 /* WMSZ_TOPRIGHT */ : return 1;
case 7 /* WMSZ_BOTTOMLEFT */ : return 3;
case 8 /* WMSZ_BOTTOMRIGHT */ : return 3;
default: return -1;
}
}
public static void SubtractWindowBorders(IntPtr hwnd, ref RECT rc, int dpi)
{
RECT r = new RECT(0, 0, 0, 0);
AddWindowBorders(hwnd, ref r, dpi);
rc.Left -= r.Left;
rc.Top -= r.Top;
rc.Right -= r.Right;
rc.Bottom -= r.Bottom;
}
public static void AddWindowBorders(IntPtr hwnd, ref RECT rc, int dpi)
{
uint windowStyle = (uint)GetWindowLong(hwnd, -16); // GWL_STYLE
uint windowStyleEx = (uint)GetWindowLong(hwnd, -20); // GWL_EXSTYLE
if (Environment.OSVersion.Version >= Windows_10_1607)
AdjustWindowRectExForDpi(ref rc, windowStyle, false, windowStyleEx, (uint)dpi);
else
AdjustWindowRect(ref rc, windowStyle, false);
}
public static int GetDPI(IntPtr hwnd)
{
if (Environment.OSVersion.Version >= Windows_10_1607)
return GetDpiForWindow(hwnd);
else
using (Graphics gx = Graphics.FromHwnd(hwnd))
return GetDeviceCaps(gx.GetHdc(), 88 /*LOGPIXELSX*/);
}
} }

View File

@@ -1,41 +0,0 @@

using System;
using static WinAPI;
namespace mpvnet
{
public static class NativeHelp
{
public static int GetResizeBorder(int v)
{
switch (v)
{
case 1 /* WMSZ_LEFT */ : return 3;
case 3 /* WMSZ_TOP */ : return 2;
case 2 /* WMSZ_RIGHT */ : return 3;
case 6 /* WMSZ_BOTTOM */ : return 2;
case 4 /* WMSZ_TOPLEFT */ : return 1;
case 5 /* WMSZ_TOPRIGHT */ : return 1;
case 7 /* WMSZ_BOTTOMLEFT */ : return 3;
case 8 /* WMSZ_BOTTOMRIGHT */ : return 3;
default: return -1;
}
}
public static void SubtractWindowBorders(IntPtr hwnd, ref RECT rc)
{
RECT r = new RECT(0, 0, 0, 0);
AddWindowBorders(hwnd, ref r);
rc.Left -= r.Left;
rc.Top -= r.Top;
rc.Right -= r.Right;
rc.Bottom -= r.Bottom;
}
public static void AddWindowBorders(IntPtr hwnd, ref RECT rc)
{
AdjustWindowRect(ref rc, (uint)GetWindowLong(hwnd, -16 /* GWL_STYLE */), false);
}
}
}

View File

@@ -10,7 +10,7 @@ using System.ComponentModel;
using System.Globalization; using System.Globalization;
using static mpvnet.Core; using static mpvnet.Core;
using static WinAPI; using static Native;
namespace mpvnet namespace mpvnet
{ {
@@ -19,12 +19,13 @@ namespace mpvnet
public static MainForm Instance { get; set; } public static MainForm Instance { get; set; }
public static IntPtr Hwnd { get; set; } public static IntPtr Hwnd { get; set; }
public new ContextMenuStripEx ContextMenu { get; set; } public new ContextMenuStripEx ContextMenu { get; set; }
Point LastCursorPosition; Point LastCursorPosition;
int LastCursorChanged;
int LastCycleFullscreen; int LastCursorChanged;
int LastAppCommand; int LastCycleFullscreen;
int TaskbarButtonCreatedMessage; int LastAppCommand;
int ShownTickCount; int TaskbarButtonCreatedMessage;
int ShownTickCount;
Taskbar Taskbar; Taskbar Taskbar;
List<string> RecentFiles; List<string> RecentFiles;
@@ -108,10 +109,18 @@ namespace mpvnet
int posX = RegistryHelp.GetInt("PosX"); int posX = RegistryHelp.GetInt("PosX");
int posY = RegistryHelp.GetInt("PosY"); int posY = RegistryHelp.GetInt("PosY");
if (posX != 0 && posY != 0 && App.RememberPosition) if ((posX != 0 || posY != 0) && App.RememberPosition)
{ {
Left = posX - Width / 2; Left = posX - Width / 2;
Top = posY - Height / 2; Top = posY - Height / 2;
int horizontal = RegistryHelp.GetInt("HorizontalLocation");
int vertical = RegistryHelp.GetInt("VerticalLocation");
if (horizontal == -1) Left = posX;
if (horizontal == 1) Left = posX - Width;
if (vertical == -1) Top = posY;
if (vertical == 1) Top = posY - Height;
} }
if (core.WindowMaximized) if (core.WindowMaximized)
@@ -452,17 +461,18 @@ namespace mpvnet
Point middlePos = new Point(Left + Width / 2, Top + Height / 2); Point middlePos = new Point(Left + Width / 2, Top + Height / 2);
var rect = new RECT(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height)); var rect = new RECT(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height));
NativeHelp.AddWindowBorders(Handle, ref rect); AddWindowBorders(Handle, ref rect, GetDPI(Handle));
int left = middlePos.X - rect.Width / 2; int left = middlePos.X - rect.Width / 2;
int top = middlePos.Y - rect.Height / 2; int top = middlePos.Y - rect.Height / 2;
Rectangle workingArea = screen.WorkingArea; Rectangle workingArea = screen.WorkingArea;
Rectangle currentRect = new Rectangle(Left, Top, Width, Height); Rectangle currentRect = new Rectangle(Left, Top, Width, Height);
if (HorizontalLocation(screen) == -1) left = Left; if (GetHorizontalLocation(screen) == -1) left = Left;
if (HorizontalLocation(screen) == 1) left = currentRect.Right - rect.Width; if (GetHorizontalLocation(screen) == 1) left = currentRect.Right - rect.Width;
if (VerticalLocation(screen) == -1) top = Top; if (GetVerticalLocation(screen) == -1) top = Top;
if (VerticalLocation(screen) == 1) top = currentRect.Bottom - rect.Height; if (GetVerticalLocation(screen) == 1) top = currentRect.Bottom - rect.Height;
Screen[] screens = Screen.AllScreens; Screen[] screens = Screen.AllScreens;
int minLeft = screens.Select(val => val.WorkingArea.X).Min(); int minLeft = screens.Select(val => val.WorkingArea.X).Min();
@@ -485,11 +495,14 @@ namespace mpvnet
SetWindowPos(Handle, IntPtr.Zero, left, top, rect.Width, rect.Height, 4); SetWindowPos(Handle, IntPtr.Zero, left, top, rect.Width, rect.Height, 4);
} }
public int HorizontalLocation(Screen screen) public int GetHorizontalLocation(Screen screen)
{ {
Rectangle workingArea = screen.WorkingArea; Rectangle workingArea = screen.WorkingArea;
Rectangle rect = new Rectangle(Left - workingArea.X, Top - workingArea.Y, Width, Height); Rectangle rect = new Rectangle(Left - workingArea.X, Top - workingArea.Y, Width, Height);
if (workingArea.Width / (float)Width < 1.2)
return 0;
if (rect.X * 3 < workingArea.Width - rect.Right) if (rect.X * 3 < workingArea.Width - rect.Right)
return -1; return -1;
@@ -499,11 +512,14 @@ namespace mpvnet
return 0; return 0;
} }
public int VerticalLocation(Screen screen) public int GetVerticalLocation(Screen screen)
{ {
Rectangle workingArea = screen.WorkingArea; Rectangle workingArea = screen.WorkingArea;
Rectangle rect = new Rectangle(Left - workingArea.X, Top - workingArea.Y, Width, Height); Rectangle rect = new Rectangle(Left - workingArea.X, Top - workingArea.Y, Width, Height);
if (workingArea.Height / (float)Height < 1.2)
return 0;
if (rect.Y * 3 < workingArea.Height - rect.Bottom) if (rect.Y * 3 < workingArea.Height - rect.Bottom)
return -1; return -1;
@@ -623,13 +639,35 @@ namespace mpvnet
{ {
if (WindowState == FormWindowState.Normal) if (WindowState == FormWindowState.Normal)
{ {
RegistryHelp.SetValue(App.RegPath, "PosX", Left + Width / 2); SavePosition();
RegistryHelp.SetValue(App.RegPath, "PosY", Top + Height / 2);
RegistryHelp.SetValue(App.RegPath, "Width", ClientSize.Width); RegistryHelp.SetValue(App.RegPath, "Width", ClientSize.Width);
RegistryHelp.SetValue(App.RegPath, "Height", ClientSize.Height); RegistryHelp.SetValue(App.RegPath, "Height", ClientSize.Height);
} }
} }
void SavePosition()
{
int posX = Left + Width / 2;
int posY = Top + Height / 2;
Screen screen = Screen.FromControl(this);
int x = GetHorizontalLocation(screen);
int y = GetVerticalLocation(screen);
if (x == -1) posX = Left;
if (x == 1) posX = Left + Width;
if (y == -1) posY = Top;
if (y == 1) posY = Top + Height;
RegistryHelp.SetInt("PosX", posX);
RegistryHelp.SetInt("PosY", posY);
RegistryHelp.SetInt("HorizontalLocation", x);
RegistryHelp.SetInt("VerticalLocation", y);
}
protected override CreateParams CreateParams { protected override CreateParams CreateParams {
get { get {
CreateParams cp = base.CreateParams; CreateParams cp = base.CreateParams;
@@ -726,27 +764,28 @@ namespace mpvnet
break; break;
case 0x0214: // WM_SIZING case 0x0214: // WM_SIZING
{ {
var rc = Marshal.PtrToStructure<RECT>(m.LParam); RECT rc = Marshal.PtrToStructure<RECT>(m.LParam);
var r = rc; RECT r = rc;
NativeHelp.SubtractWindowBorders(Handle, ref r); SubtractWindowBorders(Handle, ref r, GetDPI(Handle));
int c_w = r.Right - r.Left, c_h = r.Bottom - r.Top; int c_w = r.Right - r.Left, c_h = r.Bottom - r.Top;
Size s = core.VideoSize; Size videoSize = core.VideoSize;
if (s == Size.Empty) if (videoSize == Size.Empty)
s = new Size(16, 9); videoSize = new Size(16, 9);
float aspect = s.Width / (float)s.Height; float aspect = videoSize.Width / (float)videoSize.Height;
int d_w = (int)(c_h * aspect - c_w); int d_w = (int)(c_h * aspect - c_w);
int d_h = (int)(c_w / aspect - c_h); int d_h = (int)(c_w / aspect - c_h);
int[] d_corners = { d_w, d_h, -d_w, -d_h }; int[] d_corners = { d_w, d_h, -d_w, -d_h };
int[] corners = { rc.Left, rc.Top, rc.Right, rc.Bottom }; int[] corners = { rc.Left, rc.Top, rc.Right, rc.Bottom };
int corner = NativeHelp.GetResizeBorder(m.WParam.ToInt32()); int corner = GetResizeBorder(m.WParam.ToInt32());
if (corner >= 0) if (corner >= 0)
corners[corner] -= d_corners[corner]; corners[corner] -= d_corners[corner];
Marshal.StructureToPtr<RECT>(new RECT(corners[0], corners[1], corners[2], corners[3]), m.LParam, false); Marshal.StructureToPtr(new RECT(corners[0], corners[1], corners[2], corners[3]), m.LParam, false);
m.Result = new IntPtr(1); m.Result = new IntPtr(1);
} }
return; return;

View File

@@ -149,7 +149,6 @@
<Compile Include="mpv\core.cs" /> <Compile Include="mpv\core.cs" />
<Compile Include="Misc\Commands.cs" /> <Compile Include="Misc\Commands.cs" />
<Compile Include="Native\Native.cs" /> <Compile Include="Native\Native.cs" />
<Compile Include="Native\NativeHelp.cs" />
<Compile Include="Misc\Program.cs" /> <Compile Include="Misc\Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Native\TaskDialog.cs" /> <Compile Include="Native\TaskDialog.cs" />

View File

@@ -248,13 +248,11 @@ namespace mpvnet
if (!File.Exists(_ConfigFolder + "mpv.conf")) if (!File.Exists(_ConfigFolder + "mpv.conf"))
{ {
string conf = Properties.Resources.mpv_conf; string conf = Properties.Resources.mpv_conf;
Graphics gx = Graphics.FromHwnd(IntPtr.Zero); float scale = Native.GetDPI(IntPtr.Zero) / 96.0f;
float scale = WinAPI.GetDeviceCaps(gx.GetHdc(), 88 /*LOGPIXELSX*/) / 96.0f;
if (scale != 1) if (scale != 1)
conf = conf.Replace("console-scale=1", "console-scale=" + scale); conf = conf.Replace("console-scale=1", "console-scale=" + scale);
gx.Dispose();
File.WriteAllText(_ConfigFolder + "mpv.conf", conf); File.WriteAllText(_ConfigFolder + "mpv.conf", conf);
} }
} }
@@ -356,7 +354,7 @@ namespace mpvnet
mpv_event evt = (mpv_event)Marshal.PtrToStructure(ptr, typeof(mpv_event)); mpv_event evt = (mpv_event)Marshal.PtrToStructure(ptr, typeof(mpv_event));
if (WindowHandle == IntPtr.Zero) if (WindowHandle == IntPtr.Zero)
WindowHandle = WinAPI.FindWindowEx(MainForm.Hwnd, IntPtr.Zero, "mpv", null); WindowHandle = Native.FindWindowEx(MainForm.Hwnd, IntPtr.Zero, "mpv", null);
//Debug.WriteLine(evt.event_id.ToString()); //Debug.WriteLine(evt.event_id.ToString());
@@ -1210,9 +1208,9 @@ namespace mpvnet
string dll = Environment.GetEnvironmentVariable("AviSynthDLL"); string dll = Environment.GetEnvironmentVariable("AviSynthDLL");
if (File.Exists(dll)) if (File.Exists(dll))
WinAPI.LoadLibrary(dll); Native.LoadLibrary(dll);
else else
WinAPI.LoadLibrary("AviSynth.dll"); Native.LoadLibrary("AviSynth.dll");
WasAviSynthLoaded = true; WasAviSynthLoaded = true;
} }