shayne / PowerDimmer

Distraction dimmer for Windows ala HazeOver/LeDimmer
MIT License
74 stars 9 forks source link

DPI Multi-monitor Not Being Filled Properly #2

Closed crutchcorn closed 2 years ago

crutchcorn commented 2 years ago

I'm currently using two monitors. One at 1440p resolution with 1.0 scaling on the left. The other on the right at 4k resolution with 1.5 scaling.

When using PowerDimmer, I get the following results on the 4k screen on the right with scaling:

screen-size

However, if I change these lines to 99999999999999999, it works as-intended:

https://github.com/shayne/PowerDimmer/blob/main/DimWindow.xaml#L17-L18

It appears that SystemParameters.VirtualScreenWidth is not taking my scaling into consideration:

https://social.msdn.microsoft.com/Forums/vstudio/en-US/8952a7c1-6da2-477b-aecc-c4a6503f65e8/systemparametersvirtualscreen-returns-incorrect-values?forum=wpf

crutchcorn commented 2 years ago

I'm still quite sure that it's a DPI problem (the math on my scaling works out too well to not be) however, I'm noticing some of the following:

When running the following code to detect if DPI is being registered for each screen properly:

var size = Screen.AllScreens.Select(screen => screen.Bounds)
                .Aggregate(Rectangle.Union)
                .Size;

Then changing the .csproj file to include:

    <ApplicationHighDpiMode>PerMonitor</ApplicationHighDpiMode>

It doesn't seem to change any behavior (no matter what DPI mode I have it set to). Is this because of this issue?

https://github.com/Microsoft/WPF-Samples/tree/master/PerMonitorDPI#windowsforms-apps-not-supported

shayne commented 2 years ago

I pushed branch issue2 where I switched the method of obtaining the Width and Height for the screens. Wanna build and run that? Let me know.

happiness801 commented 2 years ago

Can confirm the scaling issue. Additionally, I have 3 monitors. One of them is to the left of the "Primary" monitor and it doesn't dim at all. If I move it to the right, or below, it dims. If it is to the left or top of Primary, it doesn't dim, so there appears to be an offset issue with multiple monitors as well.

image

Primary monitor is "2".

happiness801 commented 2 years ago

I'm also noticing that @crutchcorn 's fix doesn't work for me... the dimmer window seems to be limited to a certain width and will go no wider. Maybe it will be necessary to create a dimmer window for each monitor set to the size of that monitor? (just spit-balling)

crutchcorn commented 2 years ago

@happiness801 what if you change the left="0" and top both to "-99999999" as well?

@shayne I'll make sure to test your branch fix soon

happiness801 commented 2 years ago

@crutchcorn It actually fails to run with Width="99999999999999999" at all, it just exits. If the numbers are > ...something--haven't had time to figure out exactly the range--it just exits. I can't figure out how to get any console logging working (I'm a newb to .NET).

It just seems that my system is enforcing some sort of maxwidth and maxheight so if I put the left and right way out in negative space, the dimmer window is completely out-of-sight. Roughly playing with the numbers it seems that the max effective value I can set "width" to is somewhere around 6500 on my system. Monitor 2 is 3840 x 1440 @ 100% scaling and Monitor 1 is 3840 x 2160 @ 250% scaling.

crutchcorn commented 2 years ago

@shayne confirmed that your fix branch doesn't solve the bug

shayne commented 2 years ago

Can you provide the console output that prints what width and height it detected?

shayne commented 2 years ago

I pushed a change to the issue2 branch. Mind trying it out and letting me know?

@happiness801 two ways to get a console:

1) use vscode and ctrl-shift-f5 to run, should bring up console output,

2)

    > dotnet build
    > dotnet .\bin\Debug\net6.0-windows\PowerDimmer.dll
crutchcorn commented 2 years ago

Actually @shayne I can already tell ya without running that said method doesn't work :(

I tested that exact code not that long ago.

https://github.com/shayne/PowerDimmer/issues/2#issuecomment-1002406547

I strongly suspect it's due to DPI scaling and requires some settings with WinForm to fix it. It marks my 4k monitor as 1440 width, which is inaccurate

shayne commented 2 years ago

@crutchcorn I set my scaling to 200% on my monitor and it reports the actual (correct) resolution. Would you mind running it and sending me what the console output is?

happiness801 commented 2 years ago

@shayne - Just tried branch issue2. Issue is not fixed, console output is:

PS C:\dev\PowerDimmer> dotnet .\bin\Debug\net6.0-windows\PowerDimmer.dll
Total Size: {Width=6176, Height=1699}
UpdateDimming, handle: 1900618
happiness801 commented 2 years ago

@shayne Well, I can't tell you why, but this makes it work for me: change the width and height to "9999" in DimWindow.xaml and change this line in App.xaml.cs:

            Win32.SetWindowPos(dimWin.Handle, firstPinned ?? fgHandle, 1212, 0, 0, 0, Win32.SWP_NOSIZE | Win32.SWP_NOACTIVATE);

So, I removed Win32.SWP_NOMOVE and set the x value... it has to be 1212 or larger (but not larger than some value around 2000) and it will work for my setup. It feels like something buggy, because, yes I know, that makes no sense. If I change Monitor 1's DPI scaling from 250% to 100%, this no longer is "fixed" with these values.

shayne commented 2 years ago

After a bit of reading I believe to understand the issue here. Default behavior is that the primary display sets the DPI for the whole app. Since you two are running mixed scaling, whenever it draws on a secondary display with a different DPI/scale-factor it's drawing based on the metrics of the primary display.

I don't think the solution is per monitor awareness... unless I move to multiple dim windows (one per monitor), it wouldn't solve the problem. Instead I'll look at calculating an appropriate size based on default behavior and querying DPI and comparing it to the primary.

Stay tuned...

shayne commented 2 years ago

Plugged in a second screen and was able to repro what you two are experiencing. I agree it's DPI related. What's unusual is there seems to be a maximum virtual size I for a given window. I quickly ran into an issue where, even with correct dimensions, the dim window wouldn't stretch across both screens. I believe this to be a limit of the method and type of window (System.Windows.Window) I'm using.

I switched things around and the issue2 branch now uses multiple dim windows that are simply maximized in each screen. I've briefly tested it and it has the desired effect.

Give it a go and let me know, I'll merge it into main if you're both happy with it.

happiness801 commented 2 years ago

One dimmer per monitor was going to be my suggestion. I'm blown away you were able to change that so quickly.

It ALMOST fixes it. So I have a tiny 7" USB monitor (800x600 res) set to the left of my primary. That one still isn't dim. It looks like when it maximizes it, it maximizes it to my main monitor. I set the windows to ShowInTaskbar="True" so I could see what's going on and sure enough, there were two DimWindows on my main and none on the little monitor. I added this comment:

            foreach (var screen in System.Windows.Forms.Screen.AllScreens)
            {
                var win = new DimWindow(brightness);
                win.Left = screen.Bounds.Left;
                win.Top = screen.Bounds.Top;
                Console.WriteLine("Added dim window at {0}, {1}", win.Left, win.Top);
                dimWindows.Add(win);
            }

and it seems like it's setting it up correctly:

Added dim window at 3840, 835
Added dim window at 0, 0
Added dim window at -800, 706

But I don't know why it wouldn't maximize it on the right screen. Have you tested this with the primary monitor being on the right of others? It seems like it could be something to do with that.

UPDATE: I just tested that. I set my farthest-right (of three) monitor to primary and now all three dimmer windows are maximized to that one screen.

Something to do with trying to maximize a screen with a negative offset is the issue.

Now I see:

Added dim window at 0, 0
Added dim window at -9600, -2088
Added dim window at -11600, -323

and, on the main, furthest-right monitor (all three windows are there): image

SECOND UPDATE: hypothesis looking good. Set the left-most monitor to primary, and now it works as intended with output:

Added dim window at 4640, 129
Added dim window at 800, -706
Added dim window at 0, 0
shayne commented 2 years ago

Note renamed branch to 2-fix-multi-mon

shayne commented 2 years ago

@happiness801 give the latest commit a try. I was able to repro the issue you ran into. I simply gave the dim window a dimension of 1x1 and it behaves as expected now.

happiness801 commented 2 years ago

Sweet. Looking good!