Skip to content

Commit

Permalink
Merge pull request #98 from AnonymousII/ScreenScaling
Browse files Browse the repository at this point in the history
HighDPI Screen Scaling
  • Loading branch information
DubbleClick authored Aug 25, 2024
2 parents 976ddfb + d8b6824 commit ed01900
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 6 deletions.
29 changes: 23 additions & 6 deletions GW Launcher/Forms/MainForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,14 @@ private void NotifyIcon_MouseClick(object sender, MouseEventArgs e)
_allowVisible = true;
_keepOpen = e.Button == MouseButtons.Right && Visible == false;

//get Windows screen scale factor (system -> display -> scale):
//to get real resolution from virtual one, we need to multiply with scale factor: virtual resolution * scale = native unscaled resolution
float scale = ScreenScaling.GetScreenScalingFactor();

bool IsVisible(Point p)
{
return Screen.AllScreens.Any(s =>
p.X < s.Bounds.Right && p.X > s.Bounds.Left && p.Y > s.Bounds.Top && p.Y < s.Bounds.Bottom);
p.X < s.Bounds.Right * scale && p.X > s.Bounds.Left * scale && p.Y > s.Bounds.Top * scale && p.Y < s.Bounds.Bottom * scale);
}

var rect = NotifyIconHelper.GetIconRect(notifyIcon);
Expand All @@ -304,7 +308,7 @@ bool IsVisible(Point p)
RefreshUI();

position.X -= Width / 2;
if (position.Y > Screen.FromPoint(Cursor.Position).WorkingArea.Height / 2)
if (position.Y > Screen.FromPoint(Cursor.Position).WorkingArea.Height * scale / 2)
{
position.Y -= 5 + Height;
}
Expand All @@ -315,16 +319,29 @@ bool IsVisible(Point p)

if (!IsVisible(position))
{
position.Y = Cursor.Position.Y;
position.Y = (int) (Cursor.Position.Y * scale);
}

Debug.Assert(Screen.PrimaryScreen != null, "Screen.PrimaryScreen != null");

if (!IsVisible(position))
{
Debug.Assert(Screen.PrimaryScreen != null, "Screen.PrimaryScreen != null");
position.X = Screen.PrimaryScreen.Bounds.Width / 2;
position.Y = Screen.PrimaryScreen.Bounds.Height / 2;
position.X = (int) (Screen.PrimaryScreen.Bounds.Width * scale) / 2;
position.Y = (int) (Screen.PrimaryScreen.Bounds.Height * scale) / 2;
}

//divide out scaling factor as DPI-unaware windows app works with a virtual resolution of 100% scaling:
position.X = (int) (position.X / scale);
position.Y = (int) (position.Y / scale);

//if bottom right corner is out of screen (scaling was already divided out), move window back into screen:
if (position.X + Width > Screen.PrimaryScreen.Bounds.Width)
position.X -= position.X + Width - Screen.PrimaryScreen.Bounds.Width;

if (position.Y + Height > Screen.PrimaryScreen.Bounds.Height)
position.Y -= position.Y + Height - Screen.PrimaryScreen.Bounds.Height;


Location = position;

Visible = !Visible;
Expand Down
34 changes: 34 additions & 0 deletions GW Launcher/Utilities/ScreenScaling.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GW_Launcher.Utilities;
internal static class ScreenScaling
{
[DllImport("gdi32.dll")]
static extern int GetDeviceCaps(IntPtr hdc, int nIndex);

private enum DeviceCap
{
VERTRES = 10,
DESKTOPVERTRES = 117,
//... http://pinvoke.net/default.aspx/gdi32/GetDeviceCaps.html
}

//get screen scaling factor set under settings -> system -> screen: scaling (e.g. 225%)
public static float GetScreenScalingFactor()
{
using Graphics g = Graphics.FromHwnd(IntPtr.Zero);
IntPtr desktop = g.GetHdc();

int logicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.VERTRES); //virtual screen resolution scaled down for DPI-unaware app
int physicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.DESKTOPVERTRES); //actual screen resolution, e.g. 3840 x 2160

g.ReleaseHdc(desktop);

float screenScalingFactor = physicalScreenHeight / (float) logicalScreenHeight;
return screenScalingFactor; // e.g. 1.25 = 125%
}
}

0 comments on commit ed01900

Please sign in to comment.