Skip to content

fullscreen: Refactor fullscreen logic from the ground up; Fullscreen Controller and Fullscreen Handlers, better handle defaut and layout handled FS, add ability to default FS windows even on layout handled FS workspaces, fix many bugs related to fullscreen - #14705

Merged
vaxerski merged 140 commits into
hyprwm:mainfrom
erstarr:scroll_fullscreenReimpl
Jul 11, 2026

Conversation

@erstarr

@erstarr erstarr commented May 20, 2026

Copy link
Copy Markdown
Contributor

Describe your PR, what does it fix/add?

This PR seeks to:

  • Refactor the fullscreen logic from the ground up
    • Add a FS controller for central management of FS-unFS actions. Singleton
    • Add FullscreenHandler s - one default and one for each layout that wishes to own FS handling for their workspaces. Tied to each layout object -> one per workspace so workspaces can independently keep information about their windows and their fullscreen states.

Note: Layouts use their Fullscreen Handlers for their 'unique' fullscreen management. e.g. with scrolling you can scroll onto a FS window. When you do this, it doesn't call the controller but calls its Fullscreen Handler; the logic for managing multiple FS windows in a workspace is unique to scrolling and the logic/attributes/methods should be isolated to scrolling specific classes

Note: Handlers keep a list of FS windows in their 'area of responsibility (workspace)'.CWindow and CWorkspace no longer have their m_fullscreenState and m_hasFullscreenWindow attributes: these values returned to lua are obtained from the FS handlers that handle those windows/workspaces


  • Renames/Removals/Misc. Behaviour Changes

    • rename m_createdOverFullscreen --> m_allowedOverFullscreen to be more descriptive of its function.
    • Change m_allowedOverFullscreen logic: all windows when they are not hidden "behind" a FS window have m_allowedOverFullscreen = true. Only when they are hidden 'behind' a FS window do they have this attr = false (this works for floating windows but is iffy for tiled - all but current FS window is always hidden anyway)
    • Remove "effective mode" logic in fullscreen - remove FSMODE_MAX (and mode = 3 along with it) as a user-settable option.
  • Further Reading For Some Changes

  • FSMODE_MAX is no longer a user-facing mode, but is now a pure internal implementation detail. If a FS is requested by the client to be FSMODE_FULLSCREEN-ed while it is FSMODE_MAXIMIZED, it is considered in a special state (I called it FSMODE_MAX cuz the name already exists but it can be called something else.). It no longer has a special mode assigned to it.

This removes the confusion about what FSMODE_MAX is; and since it had no user-facing documentation about how it worked and why it existed, as well as the fact that it was really just FSMODE_FULLSCREEN as far as the user was concerned: it's moved to be a pure implementation detail now.

Requested values are now clamped to hi: FSMODE_FULLSCREEN so if users used mode = 3, it'll silently fall back to using = 2.


  • Fix a lot of bugs with scrolling FS behaviour:

    • Existing Bug: Fullscreen/Unfullscreening a floating window causes that window to be unfocusable, although it remains visible
    • Existing Bug: When fullscreen/unfullscreening a floating window while there is already a fullscreened tiled window, the floating windows that are supposed to be hidden behind the floating window are revealed. Not focusable but visible.
    • Existing Bug: Fullscreening/maximising a window already maximised/fullscreening causes the original size of the window to be lost (the colsize of the maximised/fullscreened window is saved and the original is lost)
    • Scroll Fs doesn't work with all dispatches that query fullscreen state, doesn't work with workspace rules with `f[0/1/2]
      • Test with border_size
    • Regression: Regression: windows not centered after exiting fullscreen in scrolling layout (since `96de3464`)Β #15206
    • FSing grouped windows - groupbar hiding when Fullscreen
  • Fixes for default handled FS

    • Existing Bug: Tiled FS window -> float it -> unFSes. inconsistent with Floating FS window -> tile it -> still FS
    • The hl.dsp.window.fullscreen_state({ internal = 2, client = -1, action = "toggle" }) dispatcher should be toggling but it behaves as if action = "set".
    • Fix scrolling maximise hyprtest - fix window size setting -> fix the test also
  • Misc improvements

    • When a window which is being FSed is expelled from a col when there's >1 windows in that col, make expel of that window always act the same as promote layoutmsg dispatch. It makes more sense for the expelled target to go behind its prev. col, not before it
  • New Features

    • Ability to choose to use default FS behaviour when FSing a window in layout owned FS behaviour workspace by passing the param in fullscreen dispatch from
    • Add a fullscreenHandler to hyprctl and fullscreen_handler attr to lua window class - as string.
    • Add pinFullscreened to hyprctl and lua window class



Framework

Legacy - before the decision to refactor FS logic complately

Definitions

FS -> A window that may be Either: FSMODE_FULLSCREEN or FSMODE_MAXIMIZED

fullscreen window -> A window that FSMODE_FULLSCREEN

maximised window -> A window that is FSMODE_MAXIMIZED

covering FS/fullscreen/maximised window -> A window that is both FS, and is considered by the layout as the "currently in complete view fullscreen window".
--> The default and scrolling's handling of these windows are the same: If a window completely covers the whole monitor (fullscreen) or the whole work area (maximise), but different layouts may define this in different ways.

Maximize <-> Maximise -- Although we all know which one is the correct way of saying it πŸ˜‰

FS Windows

Expose the following:

  • internal/client fullscreen modes: the fullscreen mode of the window.

    • This is set regardless of its handler (default or layout)
    • This is not enough to judge that a window is a covering FS.
  • m_target of the window has a bool m_layoutManagedFullscreen flag.

    • This must be set true if window is layout managed, false otherwise. This is used outside the FS related functions to differentiate between default and layout handled fullscreens.
  • fullscreen handler enum.

    • This is to be used to differentiate between different fullscreen handlers when/if there are more layouts that handle their own fullscreens.
      • For example: in scrolling, changing focus to another window when there's a covering FS should not cause fullscreen to cycle (depending on the config value; switch to that window after unFS, unFs current and FS the focused window, or simply unFS the current window); let's say another layout's FS behaviour would like this behaviour. We cannot use the m_layoutManagedFullscreen then, and need to carve out scrolling handled FS windows as the sole exception.
    • This can also be used to create window rules targeting only specific layout handled FS windows: I want scrolling handled FS windows to keep their borders, but don't want the default handled ones to have borders. (without this, scrolling FS windows that don't cover still get their borders stripped with a window rule that only targets fullscreen windows - which is what someone may want, or may not want)
  • isFullscreen() method.

    • This returns true IFF the window is a covering FS!
      • Note that if 2 FS windows overlap (scrolling tiled and floating example), this returns true for both; as both are indeed covering FS windows!
        • In this case, use workspace's FS method to get the FS window ontop.

Workspace

Have 2 fullscreen related attributes/methods

  • m_hasFullscreenWindow - This is true if there is a covering FS window in the workspace

  • getFullscreenWindow() - Returns the covering FS window of the workspace.

    • It is possible for 2 covering fullscreen windows to overlap. In scrolling: a tiled layout managed covering FS window and a floating (default handled) covering FS window may exist at the same time. In this case, this method returns the covering floating FS window.

Monitor

  • inFullscreenMode() - returns true if there's a covering FS window whose internal mode is FSMODE_FULLSCREEN (i.e. there's a fullscreen window)
  • getFullscreenWindow() - calls workspace method of the same name; same return val.

What FS behaviour a layout may own

A layout may own:

  • How to fullscreen a window (requestFullscreen())
  • The definition of a FS window (consequence of the layout owning requestFullscreen() and layoutFullscreenTarget())
  • How to handle window hiding upon FS (setNoMembersAboveFullscreen())
  • What defines a covering FS window (layoutFullscreenTarget())

A layout must override both requestFullscreen() and layoutFullscreenTarget() if it wished to own fullscreen behaviour, but may choose to not override setNoMembersAboveFullscreen() if it doesn't need window hiding behaviour different than the default.

Needless to say, layouts can define whatever helper functions they need internally to handle the above. All of that is isolated to the layout's own source/header files and won't be used (or ideally available) outside of it.

Layouts handle each of these with minimal mixing of default handled fullscreen related code. As it is, some code related to default handled FS windows is inevitable as floating windows are always default handled; and in a future PR I'll make it possible to have a default handled tiled FS window in workspaces that have layouts that own FS semantics.

Default Handled FS

  • The old FS behaviour - unchanged. The size and position of the window are set, its FS related window properties are set, and that's it.

All layouts that don't define their own FS behaviour will use the default handled FS behaviour.

In a future PR, i'll add the ability to choose if the user wants to use default or layout FS behaviour in workspaces whose layout does define custom FS behaviour.

Note for default handled FS with master and monocle layouts

Both of these set a window's size and pos in recalculate() calls. therefore, there is code in both their recalculate() calls to correctly set or skip re-setting window pos-size if that window is fullscreen.

Layout handled FS

  • layoutFullscreenTarget() must return the target that is FS and is covering. Even if there is a covering floating FS window ontop, it must still return the covering FS window.

    • This is used in isFullscreen() of CWindow to judge if a window is fullscreen if that window is layout handled.
  • requestFullscreen() defines how to FS/un-FS a window when the corresponding dispatch or internal call to set window's internal FS state is fired.

  • setNoMembersAboveFullscreen() can be optionally overridden if a layout needs custom window hiding logic (e.g. floating windows when there's an underlying covering layout managed tiled FS window in scrolling layout).

  • recalculate() - scrolling uses this to keep the shapes and sizes of non-covering (or focused) FS windows. I reckon other layouts that may own FS semantics in the future will also almost always make use of this.




Is there anything you want to mention? (unchecked code, possible bugs, found problems, breaking compatibility, etc.)

Complete refactor of FS and some related things. Please read the description for the full list of changes and what they imply.

Known Bugs

  • All bugs from "Fix a lot of bugs with scrolling FS behaviour:" - duplicated here for ease of viewing
    • Existing Bug: Fullscreen/Unfullscreening a floating window causes that window to be unfocusable, although it remains visible
    • Existing Bug: When fullscreen/unfullscreening a floating window while there is already a fullscreened tiled window, the floating windows that are supposed to be hidden behind the floating window are revealed. Not focusable but visible.
    • Existing Bug: Fullscreening/maximising a window already maximised/fullscreening causes the original size of the window to be lost (the colsize of the maximised/fullscreened window is saved and the original is lost)
    • Scroll Fs doesn't work with all dispatches that query fullscreen state, doesn't work with workspace rules with f[0/1/2]
    • Regression: Regression: windows not centered after exiting fullscreen in scrolling layout (since `96de3464`)Β #15206
    • FSing grouped windows - groupbar hiding when Fullscreen



MR Related Bug Tracking:

  • Scrolling - group FS doesn't work
  • new window creation (other than kitty) -> invisible until it's switch to or fullscreened
  • make a group with at least two windows -> fullscreen it -> change focus between group members -> unfullscreen it -> there are not borders until you change focus to another group member. (both for default and layout handling - default fails to resize too)
  • Default Handled fullscreen - grouped windows -> switch btw windows -> windows size is not kept at fullscreen
  • Window rules broken
  • Workspace Rules Broken (maybe?)
  • The hl.dsp.window.fullscreen_state({ internal = 2, client = -1, action = "toggle" }) dispatcher should be toggling but it behaves as if action = "set".
  • Default Handled FS -> Fullscreen window -> create floation -> fullscreen/unfullscreen floating -> floating is lost behind FS window
  • Floating grouped windwos -> FS -> Tile without unFSing -> unFS => window/workspace rules keep applying
  • in non-master layouts maximise position/size setting is broken
  • fade animations are broken
  • master -> on_focus_under_fullscreen = 0 -> maximise master, open a new tiled window. broken.



TODO

  • Case: FS a video in a browser that's maximised and unFS the video - use vid player's own controls. Browser should probably remain maximised.

Misc:

Details - [ ] When moving windows around workspaces, windows should be properly unFSed before move and re-FSed after move. This should be the current behaviour -> make sure that it is reliable
  • Replace all bitmap compare operators with == / != (????)

  • Don't forget null checks where appropriate

  • Test legacy dispatchers

  • Check that the viewport doesn't move when default FSed on scrolling

  • Additional virtual layouts may implement: syncFullscreen() - if necessary. may not need this

  • Go over the framework part and properly document the current layout fullscreen logic

  • Clear up includes and forward decelerations

  • Refactor the Tiled (no need iirc), Master, monocle recalculate to better handle not updatePos() - ing a window that's fullscreened.

  • Clear comments made during PR.

    • Clear out all commented code, artifacts and notes taken during the PR

Wiki MR TODO

  • Users can choose to default handled a window even in a workspace with layout fullscreen behaviour (scrolling) {layout_aware = bool}
  • FSMODE_MAX doesn't exist as a mode (in the enum) anymore -- it is now a state that can only be requested by clients and only sets internal value if internal and client are synced. Neither client not internal can be manually set to FSMODE_MAX; but client can be considered as FSMODE_MAX if it meets the conditions (FSMODE_MAXIMISED -> FSMODE_FULLSREEN)
  • Window rules -> f[1] matches covering FS windows. fullscreen = true matches non-covering as well.

@github-actions

Copy link
Copy Markdown

Hello and thank you for making a PR to Hyprland!

Please check the PR Guidelines and make sure your PR follows them.
It will make the entire review process faster. :)

If your code can be tested, please always add tests. See more here.

beep boop, I'm just a bot. A real human will review your PR soon.

@erstarr erstarr changed the title layout/fullscreen: Reimplement layout handled fullscreens, refactor fullscreen pipeline, generally unify and refactor fullscreen related functions layout/fullscreen: slightly reimplement and refactor layout handled fullscreens, refactor fullscreen pipeline, generally unify and refactor fullscreen related functions May 20, 2026
@erstarr erstarr changed the title layout/fullscreen: slightly reimplement and refactor layout handled fullscreens, refactor fullscreen pipeline, generally unify and refactor fullscreen related functions layout/fullscreen: slightly reimplement and refactor layout handled fullscreens, refactor fullscreen pipeline, unify fullscreen related functions May 20, 2026
@erstarr
erstarr force-pushed the scroll_fullscreenReimpl branch 2 times, most recently from d465531 to 6035f51 Compare May 22, 2026 18:18
@erstarr
erstarr force-pushed the scroll_fullscreenReimpl branch 2 times, most recently from 9a4a4b2 to e294ccc Compare May 23, 2026 17:12
@erstarr
erstarr force-pushed the scroll_fullscreenReimpl branch 4 times, most recently from c43950e to aa16287 Compare May 28, 2026 18:42
@erstarr
erstarr force-pushed the scroll_fullscreenReimpl branch from 8bc7257 to 5ecdd8d Compare May 29, 2026 12:01
@erstarr erstarr changed the title layout/fullscreen: slightly reimplement and refactor layout handled fullscreens, refactor fullscreen pipeline, unify fullscreen related functions layout/fullscreen: slightly reimplement and refactor layout handled fullscreens, refactor fullscreen pipeline, unify fullscreen related functions, reimplement window hiding upon fullscreen logic May 30, 2026
@erstarr
erstarr force-pushed the scroll_fullscreenReimpl branch from 58706b1 to 6b8b51b Compare May 31, 2026 21:08
@erstarr

erstarr commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

Will change how m_createdOverFullscreen works a little so it makes more sense. Needed to make the floating window hiding with scrolling work properly

1 - All newly created windows start with m_createdOverFullscreen = true. If it is false, it is because it is currently hidden under a FS window; otherwise it is true.

@github-actions github-actions Bot added the debug label Jun 2, 2026
@erstarr

erstarr commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

In Scrolling Layout: when a window that is the last/only window in a column is floating and the layout scrolls to a FS window, that window is left ontop of the tiled FS window. I think this is a good idea, as it's unlikely that the user would want to lose that window they just floated.

@erstarr

erstarr commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

It's almost done. Only some edge case bug fixes, polish, and cleanup remains unless I also add in this PR the ability to default FS windows in workspaces with layout managed FS's available.

Just about everything else works now, so please help test!

@erstarr
erstarr force-pushed the scroll_fullscreenReimpl branch from 1a3cbae to eaaa5a7 Compare June 4, 2026 00:13
@erstarr

erstarr commented Jun 4, 2026

Copy link
Copy Markdown
Contributor Author

I'm marking this as ready for now. Mainly to hopefully get more ppl testing and have vax have a look over the code if he approves of the general changes.

Still need to do some comment cleanup, need to look into some hyprtests, and play with windowrules a bit to see if all is good; but the broad strokes should be gtg.

Hopefully more people help test if it's marked as ready too.

@erstarr
erstarr marked this pull request as ready for review June 4, 2026 00:46
erstarr added 4 commits July 10, 2026 19:35
…onsistency, fix spelling mistake, add null check for handlers to `getFsHandlersForWorkspace`, clarification comment for `getCurrentWorkspace()`, format
@erstarr

erstarr commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

done

@vaxerski

Copy link
Copy Markdown
Member

@codex review please

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ’‘ Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e5448d24d5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with πŸ‘.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/managers/fullscreen/FullscreenController.cpp Outdated
Comment thread src/desktop/view/Window.cpp Outdated
Comment thread src/desktop/view/Group.cpp Outdated
VRR in def handler
FS layout handled state preserved on FS window unmap
Groups adding to group maintains group's layout FS handler state
@erstarr

erstarr commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

done

@vaxerski

Copy link
Copy Markdown
Member

@codex review please

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ’‘ Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b595f07164

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with πŸ‘.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/layout/target/WindowTarget.cpp
Comment thread src/config/lua/bindings/LuaBindingsDispatchers.cpp
Comment thread src/managers/fullscreen/FullscreenController.cpp
@erstarr

erstarr commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Reviewed. Didn't find any bugs this time. Really useful tho, thanks for the runs.

Actually wait i have an idea for the first one let me try to handle that. The other two are not bugs

Scrolling already does because its pos setting happens in its recalc.
@erstarr

erstarr commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Done.

I really want to avoid slapping a setGlobalPos() in recalculate() if i can help it.

@vaxerski

Copy link
Copy Markdown
Member

@codex review please

@vaxerski

Copy link
Copy Markdown
Member

really want to avoid slapping a setGlobalPos() in recalculate() if i can help it.

yeah, but you could've just added some rechec() but oh well this works ig

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ’‘ Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6de59cedfc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with πŸ‘.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/layout/algorithm/tiled/scrolling/ScrollingFullscreenHandler.hpp Outdated
Comment thread src/layout/algorithm/tiled/scrolling/ScrollingFullscreenHandler.cpp Outdated
- Initalise Vars
- respect VRR config opts in recalc setting VRR if scrolling onto or have a new FS window
@erstarr

erstarr commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

done

@vaxerski

Copy link
Copy Markdown
Member

@codex review please

@vaxerski

Copy link
Copy Markdown
Member

shame it cant do more at once

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ’‘ Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 25c2b4e0de

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with πŸ‘.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/config/shared/actions/ConfigActions.cpp
@erstarr

erstarr commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Repeated (#14705 (comment)). Guess it's a good sign that it only gave this

I'm unsatisfied with pos setting with changing work area so I'll redo that. Otherwise, if the oracle gives its blessings, merge at your discretion.

edit: done.

p.s. visible is very finicky and it's hard to test the visibility of a window with it. Used visible, hidden, acceptInput in combination to compensate. Will look into it but it doesn't need to hold this MR up since the other 2 confirm proper behaviour.

erstarr added 3 commits July 11, 2026 04:21
Replace all calls to default handler from algorithms with controller() calls that include error correction logic - Scrolling is an exception as its handling is radically different

Extract repeated code into helper
Fix minor bugs

@vaxerski vaxerski left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants