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

Add per-window content scaling #9428

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

Add per-window content scaling #9428

wants to merge 3 commits into from

Conversation

dawsers
Copy link
Contributor

@dawsers dawsers commented Feb 17, 2025

Add a new dispatcher scaleactive that scales the content of the active window

per-window_scaling

Each window can have its contents with a different scale. This can be useful for background apps/jobs you want to control and you don't want them to take much space, pinned windows etc. You can also use it for applications that have their UI too big or too small and don't support native re-scaling.

I don't think I have covered every case yet, but I wanted to propose this initial PR so you guys tell me if there is any real interest for this before I spend more time in it. I was going to implement this in hyprscroller, but it made more sense to integrate the feature in Hyprland.

There is currently a bug that I haven't figured out: Sometimes the client renders popups to be "inside the monitor", so despite the window being visible and interactive, some popups render in what would be the non-scaled monitor extents. I can attach an image if there is any interest to help.

The change should be transparent. By default the scale is 1.0, so it shouldn't interfere with Hyprland unless changed.

To try it out, add something like this to your config:

# Scaling submap
# will switch to a submap called scaling
bind = $mainMod, period, submap, scaling
# will start a submap called "scaling"
submap = scaling
# sets repeatable binds for scaling the content of the active window
bind = , 1, scaleactive, 0.4 
bind = , 1, submap, reset
bind = , 2, scaleactive, 0.6
bind = , 2, submap, reset
bind = , 3, scaleactive, 0.8
bind = , 3, submap, reset
bind = , 4, scaleactive, 1.25
bind = , 4, submap, reset
bind = , 5, scaleactive, 1.5
bind = , 5, submap, reset
bind = , 6, scaleactive, 2.0
bind = , 6, submap, reset
bind = , 0, scaleactive, -1.0
bind = , 0, submap, reset
# use reset to go back to the global submap
bind = , escape, submap, reset
# will reset the submap, meaning end the current one and return to the global one
submap = reset

#bind = $mainMode, period, scroller:scaleactive, 0.5
bind = $mainMode, comma, scaleactive, -1

The dispatcher accepts any positive floating point number as scale. Using a negative number (-1 by convention) will reset the scale of the content of that window. The scale has the same meaning as the fractional value for the monitor: 2 would make the content 2x2 times bigger. 0.5 would make it smaller.

Thanks!

Copy link
Member

@vaxerski vaxerski left a comment

Choose a reason for hiding this comment

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

some general design remarks:

  • consider adding a window rule for this (see prop window rules) then the dispatcher would be to override it.
  • we're adding the conentScale param everywhere - no better method? in most cases, it could be read from the window param.

No style nits for now, general design needs some work

@dawsers
Copy link
Contributor Author

dawsers commented Feb 18, 2025

Thank you for your prompt review.

I have added the window rule and modified the dispatcher to only override it. I think I am not missing anything, but please let me know if you find something strange. The only difference with other WindowData properties is this one needs to trigger a sendWindowSize() call every time the property changes, so I had to create a specific entry in the window rule check instead of relying on the default for properties.

About having to add contentScale as a parameter to a few functions, I tried not to. I think I only added it to those that didn't have access to a window:

std::pair<SP<CWLSurfaceResource>, Vector2D> CWLSurfaceResource::at(const Vector2D& localCoords, bool allowsInput, double scale)

This function can be called for any type of surface, either attached to a window or to a layer, I don't think I can remove the parameter.

void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, PHLMONITOR pMonitor, bool main, const Vector2D& projSize, const Vector2D& projSizeUnscaled, bool fixMisalignedFSV1, float contentScale);

This function is called by CSurfacePassElement::draw(), and sometimes there is no window there either.

I don't think I have added any more parameters to functions, but let me know if I am mistaken or any of those can be removed somehow I haven't figured out.

Thanks!

@SNAKESLIGHT
Copy link

Would love to see the ability to use a relative float such as +0.2, similar to what the splitratio dispatcher accepts. That way you could bind + and - to scale a window.

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.

4 participants