Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some way to disallow windows to render in a different workspace while being animated #8349

Closed
dawsers opened this issue Nov 4, 2024 · 6 comments
Labels
enhancement New feature or request

Comments

@dawsers
Copy link
Contributor

dawsers commented Nov 4, 2024

Description

The logic to decide whether a window should render for a certain monitor is in shouldRenderWindow()

For windows being animated, if the window's bounding box touches the extents of the monitor, they will be rendered (last if statement. This is to be able to see the animation of a window moving from one workspace to another.

This is OK for tiled windows, because they will never have any part outside of their monitor.

However, this creates an unwanted side-effect for cases where windows can exist outside of the monitor extents, but only belong to a workspace. In my plugin hyprscroller, there is an infinite canvas for each workspace. When a window is being animated (focus change, for example), if a part of it overlaps a different monitor, it will be rendered there, creating a very inconvenient glitch for the length of the animation.

I have tried to modify the logic of CHyprRender::shouldRenderWindow() and add an extra check in the last if statement to verify the monitor's workspace is the same as the window's.

    if (pWindow->m_vRealPosition.isBeingAnimated()) {
.........
        const CBox monitorBox = {pMonitor->vecPosition, pMonitor->vecSize};
        if (!windowBox.intersection(monitorBox).empty() && pWindow->workspaceID() == pMonitor->activeWorkspaceID())
            return true;
    }

But this introduces a problem: windows that are traversing the monitor because of an animation (moved, etc), will not be rendered in that monitor, only in the receiving one.

So I am stuck and think maybe there is a need for some other flag or field that defines when a window is being animated and needs to be shown or not. I tried to use m_iMonitorMovedFrom and m_bAnimatingIn, but they seems to be for other purposes and were not being set for those animated windows that needed to be rendered.

@vaxerski
Copy link
Member

vaxerski commented Nov 5, 2024

maybe you can check if the workspace is visible instead? g_pCompositor->isWorkspaceVisible(pWindow->workspaceID())?

I am not sure I understand what you mean here exactly

@dawsers
Copy link
Contributor Author

dawsers commented Nov 5, 2024

Yes, I may have not explained myself very well. I am going to try to go step by step:

There is a function, shouldRenderWindow() that deals with accepting/discarding which windows get rendered for many, very different cases.

  1. We have a desktop with two monitors: "WAYLAND-1" is showing workspace 1, "WAYLAND-2" is showing workspace 2.

I want to consider the difference in state from two windows:

  • One is a hyprscroller window whose boundaries extend more than WAYLAND-1, and overlap WAYLAND-2. Note that this window should only be shown in WAYLAND-1. There is an "infinite" canvas, but one for each monitor.
  • The other is a regular Hyprland animating window moving from WAYLAND-2 to WAYLAND-1
  1. hyprscroller's window is in monitor "WAYLAND-1" and workspace 1, animated window is moving from "WAYLAND-2" to "WAYLAND-1".

When there is no animation, both windows are treated correctly, hyprscroller's will be clipped correctly to WAYLAND-1, and Hyprland's animating window will be shown where it corresponds. None of the windows reach the last if statement of souldRenderWindow(), they are accepted earlier and clipped correctly.

Now we consider when these two windows are animated, hyprscroller's maybe because there was a change of focus; Hyprland's because it is moving from one workspace to the other. They both reach the last if statement:

        const CBox monitorBox = {pMonitor->vecPosition, pMonitor->vecSize};
        if (!windowBox.intersection(monitorBox).empty())
            return true;
  1. We are rendering "WAYLAND-2", These are the states of Hyprland at
    shouldRenderWindow(), last if statement whose purpose is to return true when animating a
    window:
// hyprscroller's window, Hyprland animated window:

pMonitor->szName: "WAYLAND-2", "WAYLAND-2"

pWindow->workspaceID(): 1, 1 (it's going to 1 from 2)
pMonitor->activeWorkspaceID(): 2, 2 ("WAYLAND-2" is showing workspace 2)

windowBox.intersection(monitorBox).empty(): false, false (they both intersect the monitor's viewport)

g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace): true, true (they are both assigned to workspace 1, which is visible in "WAYLAND-1")

I also checked if any of these flags were set when a window was being animated
from one workspace to another (to filter out the window we want shown
-Hyprland's original purpose-):

pWindow->m_iMonitorMovedFrom: -1, -1
pWindow->m_iLastWorkspace: -1, -1

pWindow->m_bAnimatingIn: false, false

So none of those other flags help with discerning if a window is genuinely being animated. Both cases show exactly the same state. To fix hyprscroller, I changed the last if statement to

        const CBox monitorBox = {pMonitor->vecPosition, pMonitor->vecSize};
        if (!windowBox.intersection(monitorBox).empty() && pWindow->workspaceID() == pMonitor->activeWorkspaceID())
            return true;

but that of course only shows Hyprland's window in the destination workspace, not rendering it in the workspace from which it's moving...so...fail!

And here is when I ask for your opinion:

  • Is there any way for me to know if a window is being animated "for a purpose"?
  • Should there be another flag?
  • Should any of those flags I mention (m_iMonitorMovedFrom, m_iLastWorkspace, m_bAnimatingIn ) be updated to show a window is being animated "for a purpose"?

@vaxerski: Thanks a lot for staying on top of things and helping out.

@vaxerski
Copy link
Member

vaxerski commented Nov 5, 2024

Is there any way for me to know if a window is being animated "for a purpose"?

Nope.

Should there be another flag?

hm, no, dont think so. What if you just pWindow->workspaceID() == pMonitor->activeWorkspaceID() && !pWindow->m_bIsFloating? I am trying to think of things it may break but can't really think of any. Worth checking.

Should any of those flags I mention (m_iMonitorMovedFrom, m_iLastWorkspace, m_bAnimatingIn ) be updated to show a window is being animated "for a purpose"?

animatingIn = opening
movedfrom = silent workspace moves
lastworkspace = navigation reasons iirc

@dawsers
Copy link
Contributor Author

dawsers commented Nov 5, 2024

None of the two windows are floating, so it will render the hyprscroller window correctly, but it still won't show Hyprland's window in WAYLAND-2, only in WAYLAND-1. Hyprland's window is not floating, just animating its transition from WAYLAND-2 (workspace 2) to WAYLAND-1 (workspace 1).

@vaxerski
Copy link
Member

vaxerski commented Nov 5, 2024

maybe set m_iMonitorMovedFrom every workspace change and only animate on both monitors if m_iMonitorMovedFrom != monitorID()?

@dawsers
Copy link
Contributor Author

dawsers commented Nov 5, 2024

OK, #8359 seems to fix it.

While a window is moving, its m_iMonitorMovedFrom is different than -1, so it will be rendered.
hyprscroller windows will have -1, but they will only be rendered in their corresponding monitors (workspace assigned).

@dawsers dawsers closed this as completed Nov 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants