Rearranged windows & forgotten layout after wake from sleep
Describe the bug After waking from sleep, FancyWM doesn't remember the layouts of the windows or stacks.
To Reproduce Steps to reproduce the behavior: Arrange your windows to your liking then sleep and wake, things will be all over the place.
Expected behavior Windows and arrangements should be remembered after waking from sleep.
Screenshots Here is a video demonstrating the issue.
Desktop (please complete the following information): Windows 11 22621 FancyWM 2.11.6
This issue is stale because it has been open for 14 days with no activity.
Can you please attach the log file as well. I'm not sure why you're seeing what you're seeing, but the logs can help explain.
The log file will be fancywm.log in the settings directory.
This issue seems to also occur if you unplug a monitor and plug it back in. Windows positions are not remembered.
This unfortunately happens to me too. My log files tells me nothing:
2024-05-26 09:27:33.755 +02:00 [WRN] FancyWM v2.12.1.1 (https://www.microsoft.com/store/apps/9P1741LKHQS9) on Microsoft Windows NT 10.0.22631.0 2024-05-26 09:27:34.803 +02:00 [WRN] Using the multi-monitor tiling backend
Thanks @coffeeneed. I suspect this is related to OS seeing that the monitor is being switched off and on, in which case the window state will be cleared.
I cannot think of a clear mitigation - a user might genuinely unplug a monitor, and in that case, windows will be moved to the visible area. Perhaps we can retain the layout in case of 0 monitors connected, but will need more info to know for sure.
I could add some extra logging around that area of the code, and with the help of a volunteer, capture logs to use to create a possible fix.
@veselink1 Thank you for the follow-up. I've done some research and basically concluded the same as you. I also understood that, in some circumstances, this behavior could manifest differently on DP vs. HDMI. However, this hasn't been tested from my part.
I'm talking way out of me league here, but aren't there any way in the Windows API to check for monitor or hybernation wake-ups (what ever)? If that's the case, why couldn't you listen for change in that and automatically rearrange the Windows back to its position -- which is derived from the last stored information of such data?
Again, there's probably a reason this hasn't been done already, so please forgive me for being "Captain Obvious" here.
Hi all, FancyWM is REALLY great, but at one of my workplaces I do have a multi-monitor setup (notebook with one internal display and two external monitors via usb-c docking station), and after lock/un-lock the tile are all messed up and squeezed onto the main monitor. I had a similar issues with general window placements on stock win10/win11, but somehow (maybe due to the new "Snap Windows" functionality?) the windows get now restored correctly after wake up.
Unfortunately the tiles are so messed up that it's not usable for me in this way. new "vertical" tiles get added and windows from (formerly) other monitors get added randomly(?) in these groups.
Complete Log file after starting FancyWM, creating some tiles, lock ( & wait for monitors to sleep) and then unlock
2025-01-08 12:52:35.114 +01:00 [WRN] FancyWM v2.14.0.31 (https://www.microsoft.com/store/apps/9P1741LKHQS9) on Microsoft Windows NT 10.0.22631.0
2025-01-08 12:52:36.522 +01:00 [WRN] Using the multi-monitor tiling backend
2025-01-08 12:55:17.556 +01:00 [WRN] New active display Win32Display { \\.\DISPLAY5 } is not associated with a tiling service!
Here's a screenshot AFTER the restore with some of these "stray" tile configurations, none of the "Horizontal"/"Vertical" groups existed before, just tow windows tiled side-by-side.
~~I found a "Workaround"... well, not really, but maybe it helps to implement a solution for this issue. I can avoid the problem and restore my exact layout when I do the following~~
- before locking : exit FancyWM - ~~all windows get rearranged to whatever position~~
- lock and wait for monitors to go to sleep
- unlock : windows a in the "unmanaged" position as they were after exiting FancyWM
- start FancyWM again
~~et voilá: all window tiles get restored correctly.~~
~~Assumption: it's a timing issue that right after unlocking not all monitors are re-registered but FancyWM already initializes again. IF it would be possible to wait with the re-initialization a while after unlocking then we could at least avoid the issue. Just a thought.~~
Some additional info: I've also tried to disable "Window Management" (default key F11) before locking, but after unlocking it seems to get enabled automatically and the same messed up tiling layout appears.
UPDATE Wrong assumption: it was by accident that the layout was similar after restarting FancyWM, with more complex layouts it doesn't work as FancyWM does not remember the layout but re-initializes from scratch. If the windows have been left similar to they FancyWM layout after stoping the FancyWM process, then the re-initialization results in a quite similar layout. So this helps for very simple layouts but does not really help to find a more general solution :-(.
I leave my wrong analysis here fore reference.
Hi everyone, I took a shot at fixing this issue : here's my preliminary attempt to get it going
https://github.com/FancyWM/fancywm/compare/main...ckolumbus:fancywm:fix/236-handle-window-rearrange-after-wakeup-from-sleep
It's not production ready, but lays out a possible strategy to address this issue. Here are short description on how it works
Analysis: The problem is rooted in the fact, that the display instances change after wakeup, they still have the same device name, but are not "Equal". This leads to removal of the entries in the m_tilingServices collection, rearranging all windows with it. Later a new instance with the same device name is added, but then it's too late, the layout has been messed up already.
Solution Strategy Part 1:
- don't delete entries in the m_tilingServices, but only mark them as "stale", keeping the associated TilingService
- when a new Display is added, search the stale entries to see whether one exist with the same device name and if so, copy the TilingService from the stale entry to the new one
- clean-up of stale entries is done when the transfer AND the removal has been both triggered (obviously this does not cover the complete disconnect of a display)
Solution Strategy Part 2: Part 1 is not enough, because after a wakeup the LayoutRefresh is executed too early, messing up the layout again, so Part 2 is
- hook into PowerStateChange & SessionSwitch events
- "freeze" tiling on lock/suspend
- "unfreeze" tiling after unlock/resume with delay of a few seconds so that windows had enough time to un-/register all displays
- in addition: don't explicitly invalidate the window locations after coming out of a lock/suspend when "unfreezing" to explicitly avoid rearranging the windows
currently the "start/stop" Tiling functions has been mis-used to implement Part 2. This is just a proof of concept to see whether the strategy works.
Any feedback regarding this approach and its feasibility to be a solution to the reported bug is very welcome!
Happy Coding Chris
PS: FancyWM is REALLY COOL, especially the support for Windows Virtual Desktops, which I use a lot. Other window managers stay away from this as it's not an official API. So a thousend 👍 from my side!
Hey @ckolumbus, Thanks for looking into this.
The problem is rooted in the fact, that the display instances change after wakeup, they still have the same device name, but are not "Equal". This leads to removal of the entries in the m_tilingServices collection, rearranging all windows with it. Later a new instance with the same device name is added, but then it's too late, the layout has been messed up already.
That's exactly right.
obviously this does not cover the complete disconnect of a display
Yes, I think your solution is good. A final solution that can make it into FancyWM will have to take care of this. There is another interesting and similar case, which one can observe in day-to-day and that is monitor temporary disconnect / cable issue.
I think a good solution to this problem will handle both, and will likely take an approach similar to what you have already - retaining the state of the windows, and being able to restore it when a same-named monitor connects (with some TTL maybe).
It's on my to-do list.