Skip to content

w32_common: force DWMWA_EXTENDED_FRAME_BOUNDS to work on init#17591

Merged
kasper93 merged 2 commits intompv-player:masterfrom
kasper93:win32-invis
Mar 17, 2026
Merged

w32_common: force DWMWA_EXTENDED_FRAME_BOUNDS to work on init#17591
kasper93 merged 2 commits intompv-player:masterfrom
kasper93:win32-invis

Conversation

@kasper93
Copy link
Member

No description provided.

@kasper93
Copy link
Member Author

kasper93 commented Mar 16, 2026

@Sneakpeakcss: Please, try this one, if it works fine for you.

@Sneakpeakcss
Copy link

This is kind of becoming a cat-and-mouse situation. While this does fix the geometry, it introduces new issues that are even worse imo.

Now the opening window animation is completely gone. This seems to be a wanted behaviour for some reason, even though it goes against system settings, but at the same time it is quite confusing because this animation was working fine before and after #16127 was merged. Only this PR changes that.

One of the issues is the mentioned white flash, which i can now confirm does really happen, although very rarely when opening mpv in idle mode. I can only assume that for most people this is basically a non-issue, but if your workflow constantly involves opening new instances then it becomes less so, especially when it is a newly introduced behaviour.

But even besides that, there is an even bigger problem.

The cursor position is now completely ignored when opening mpv through file explorer/taskbar.

In a multi-monitor setup, opening mpv via the pinned taskbar icon or opening files through explorer with a double click/ENTER would previously place the window on the screen where the cursor was located. The only exceptions (that i'm aware of) were opening through the terminal, or dragging a file over mpv.exe, though the latter is so obscure that it's not even worth taking into consideration.

Now with this fix, mpv always opens on the main screen, which is more of a breaking behaviour because it completely changes the workflow.

@kasper93
Copy link
Member Author

This is kind of becoming a cat-and-mouse situation.

Always has been. You have no idea how many corner case and annoying behaviors I was fighting with.

I've updated the PR to make it do the double resize differently, this should resolve your issue. However I never know when is now, if it was issues after this PR or the master now. Anyhow, give it a go.

@Sneakpeakcss
Copy link

I've updated the PR to make it do the double resize differently, this should resolve your issue. However I never know when is now, if it was issues after this PR or the master now. Anyhow, give it a go.

Nice, that fixed it. Thanks for that. And every instance of now here is related to this PR only, i try my best to do my due diligence when testing those things in a manner that excludes other factors, so it doesn't get mixed up with previous changes.

Always has been. You have no idea how many corner case and annoying behaviors I was fighting with.

You mean like the one where geometry ignores monitor offset when moving between screens? Can we get a fix on that one so i don't get an aneurysm every time i remind myself of it ;)

I can somewhat relate, but from a different perspective: https://github.com/Sneakpeakcss/mpv-window-positioning

My lovely thingy built on a stacked-up race conditions and the documented no-no of parsing logs, basically the reason why i'm aware of all those weird edge cases that i've mentioned recently.
#16127 already threw a wrench into it by removing certain logs and changing timings, forcing me to do even more terrible things to keep it working, but that's the life of a hack trying to implement a feature through a script. I can only hope that one day someone who actually knows what they're doing will get an anger fueled motivation to implement this natively, similar to what happened with the context menu and what seems to be happening to thumbnails now.

I've lost this piece of code when doing rebases or testing. This is
needed to correctly calc maximized window size.
DWMWA_EXTENDED_FRAME_BOUNDS is not available before window is shown, so
show it off-screen to get correct values.

Fixes: mpv-player#16127 (comment)
@kasper93 kasper93 merged commit 3d4170b into mpv-player:master Mar 17, 2026
29 checks passed
@kasper93 kasper93 deleted the win32-invis branch March 17, 2026 09:13
@kasper93
Copy link
Member Author

I can only hope that one day someone who actually knows what they're doing will get an anger fueled motivation to implement this natively, similar to what happened with the context menu and what seems to be happening to thumbnails now.

I can work on things, but I don't have will power to reverse usecases and find what is wrong with them. I need simple steps to reproduce the issue.

In your script for example, I don't know why you need to do all those things, instead of saving window state and setting geometry/other props on init next time.

@Sneakpeakcss
Copy link

In your script for example, I don't know why you need to do all those things, instead of saving window state and setting geometry/other props on init next time.

I've fought with this around a year ago, but going off memory, it's mostly related to how geometry works based on which monitor it's launched on. That forced me to avoid using it and complicated things a lot.

Let's assume a 2 monitor setup: 0=1920x1080(PRIMARY) and 1=1920x1080, with no-border for an easier example.

Opening mpv through the terminal as mentioned above always opens mpv on the primary monitor. So with geometry=0:0, it will obviously place it in the corner as expected, and geometry=1920:0 will place it in the corner of the secondary monitor, and as far, everything works fine (*). However, the issue starts with the behaviour mentioned above where the mpv window can also open based on the mouse cursor.

For example, opening it through the taskbar on the secondary monitor with geometry=1920:0 will move it to position 3840:0. In comparison, SetWindowPos would place it at the expected corner of the secondary monitor regardless of which monitor mpv was launched on, making things a lot easier for me.

From what i remember, i kinda(?) worked around this by detecting which display is set as primary(0:0) and basically forcing mpv to always open on it using --screen, but then the issue above happened:

(*)

geometry ignores monitor offset when moving between screens.

Now, if you set a monitor 'offset' in Windows Display Settings:

DisplaySettings

Here you can CLEARLY see that DISPLAY2 is 10 pixels higher than DISPLAY1, so now using geometry=1920:0 from primary ends up with this:

noborder border

And if you go back to the DISPLAY1 corner, you can't simply use geometry=0:0, you would have to use geometry=-1920:0, and with that -10 offset, it instead puts the window out of bounds 10 pixels higher.

So, from my limited understanding, geometry doesn’t act like SetWindowPos. It basically moves the window relative to its current position and doesn't take this 10px monitor offset into consideration, making things very wonky (and it probably gets even worse in setups with different resolutions and bigger offsets). And to be clear, this isn't a new behaviour related to any recent changes, this has been behaving like that for a long time. And with geometry, it's basically arcane knowledge what is expected and what isn't.

This is basically what killed the idea of simply using geometry and letting it manage everything without me doing inane amounts of calculations for SetWindowPos. There’s probably a way to work around this, but it's clearly beyond my abilities since this defeated me, and there’s a difference between doing something that works and doing it correctly, and i certainly fall into the former with my hobby-level, trial-and-error tinkering.

Also, i just checked how well does geometry work when moving between screens with different DPI…

From primary 96dpi to secondary 120dpi

[cplayer] Set property: geometry=640x480+1920+0 -> 1
[vo/gpu-next/win32] DPI detected from the new API: 120
[vo/gpu-next/win32] DPI detected from the new API: 96
[vo/gpu-next/win32] Window size changed to: 3840:-10:640:480
[vo/gpu-next/win32] Window size changed to: 1920:0:640:480

Well, that pos ain't right… Something, something, edge case. Powodzenia :^)

This is great, it basically first jumps to the expected corner of the secondary monitor, and then on DPI change seems to reapply the geometry, which works fine for getting the expected window size, but also triggers the described issue by reapplying the position from the secondary monitor, moving it out of bounds to position 3840. And in no-border mode it even detects a second DPI change from a non-existent monitor. Amazing, i'm getting terrible flashbacks.


Unrelated to the geometry issue, mostly ramble related to the script about limitation in a single case that pushed me to parse logs:

The other issue i've encountered is one of the listed limitations related to the case where a user moves the window without resizing it, enters fullscreen, and then closes mpv while in fullscreen state.

The expectation is that the new windowed position (after moving) should be the one it restores to on the next launch. And as far as i gathered, there's no event remotely close to "before entering fullscreen", and observing it is too slow to capture the pre-fullscreen position. Every API call i've tried is unreliable on the very first fullscreen toggle.

This basically forced me originally to do the big no-no of parsing verbose logs, because conveniently save window bounds was printed with exactly what's needed for that single fullscreen case. Unfortunately, i’ve been finally reminded of why the docs caution against doing such things.

In the current state, after #16127, it has turned from the no-no of parsing a reliable message into a racey no-no of using the Set property: fullscreen message as a trigger, simply because it's faster than the observer. Lovely.

The whole script would be way leaner and less of a hacky mess if mpv exposed its fs/min/max restoration pos/size and if the above geometry offset issue was somehow resolved. We can pretend that the DPI issue doesn't exist for everyone's sanity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants