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

Blur-Behind / Glassy Windows #538

Open
haudan opened this issue May 28, 2018 · 27 comments
Open

Blur-Behind / Glassy Windows #538

haudan opened this issue May 28, 2018 · 27 comments
Labels
DS - macos DS - windows DS - x11 H - help wanted Someone please save us S - enhancement Wouldn't this be the coolest?

Comments

@haudan
Copy link

haudan commented May 28, 2018

Moved from rust-windowing/glutin#875
Possibly related to #260

About

Glassy windows are similar to transparent windows. They let the user see through the client area of the window, exposing whatever is behind it. The difference to transparent windows is, that glassy windows have a blur-filter applied to them.

The effect can look something like this or this.

Transparency and blur are mutually exclusive.

Implementation

On Windows, the WinAPI function DwmEnableBlurBehindWindow can be used to create the blur-behind effect (I think). On OS X, NSVisualEffectView is the way to do it.
Personally I don't know how to achieve the effect on X11, but I'm sure it's possible there as well.

Library wise this could be exposed via a new function to the WindowBuilder struct. The question being is: What do we specifiy as the parameters? Since the blur effect can be customized to achieve a specific look and feel, passing a bool is probably not sufficient.

Further

Both of the Windows and OS X functions above only affect the client area of the window, however on both systems the title bar (and on Windows the border) can be made blurred as well.

It would probably be a good idea to implement seperate functions for controlling the client area and title bar / border blur.

Generally, I propose 2 functions similar to this:

fn with_client_blur(self, tbd.) -> WindowBuilder<'a>;
fn with_decoration_blur(self, tbd.) -> WindowBuilder<'a>;

Names and signatures are of course debatable.

Comments and thoughts appreciated!

Appendix 1

I have done some more research and found that on Windows 10, the undocumented function SetWindowCompositionAttribute needs to be used, as DwmEnableBlurBehindWindow is deprecated and does not properly work anymore on Windows 10. This function is is implemented in user32.dll.

@francesca64 francesca64 added S - enhancement Wouldn't this be the coolest? H - help wanted Someone please save us DS - windows C - needs discussion Direction must be ironed out D - hard Likely harder than most tasks here P - normal Great to have labels May 28, 2018
@haudan
Copy link
Author

haudan commented May 30, 2018

I updated the second example link, the old one was invalid.


I'd be happy to implement this. Any pointers / suggestions to someone new to this codebase?

@francesca64
Copy link
Member

I'd be happy to implement this

Great! I haven't really had any substantial PRs to review in weeks now, and it's been getting lonely.

Any pointers / suggestions to someone new to this codebase?

Well, IMO the Windows backend is currently the messiest, so you have that to look forward to. I took a look into SetWindowCompositionAttribute in the past, and it's presently missing from winapi (among some other related things) so you'll have to take care of that by hand (and ideally upstream it after you're sure it works, which also has the benefit of your bindings getting additional review). As long as everything you do is allowed to (and only needs to) happen on the window thread, you shouldn't have to deal with too much complexity in winit's internals, which I think will be the case here.

Adding things like this to the macOS backend is usually pretty easy, at least once you understand the Obj-C concepts and how they're applied through Rust. I guess you'd change WinitView to be a subclass of NSVisualEffectView? And then it should just be a matter of using msg_send! to change the relevant properties.

I'm not optimistic about an API existing for doing this on X11, so you should probably put this functionality behind WindowBuilderExt. Feel free to be creative with the parameters, but if you can't think of an intuitive way to generalize the API for Windows and macOS, then I'd prefer you use different APIs for each that map more transparently to the platform APIs.

If you have any questions (big or small) I'll do my best to answer them.

@OvermindDL1
Copy link

As for X11, this wouldn't really be a call to X11 itself, nor would it be preferable considering how much is switching to wayland recently, but rather this could be defined by flags given to Qt based engines like KDE, and GTK based engines have a similar way as well.

@francesca64
Copy link
Member

nor would it be preferable considering how much is switching to wayland recently

It's still going to be a long time before the majority of Linux users are on Wayland, and an even longer time before the majority of applications people run will natively use Wayland.

this could be defined by flags given to Qt based engines like KDE, and GTK based engines have a similar way as well

Are you talking about compositors?

@OvermindDL1
Copy link

It's still going to be a long time before the majority of Linux users are on Wayland, and an even longer time before the majority of applications people run will natively use Wayland.

True, but there are still such people (I am not one, my GPU is too old...), I've already had to deal with such issues (which is fun considering I can't run wayland at all, KDE has built a headless wayland compositor that I need to install sometime so I can run tests properly, think of it as xvfb but for wayland...).

Are you talking about compositors?

Correct. There aren't any other ways that I've come across that are even remotely standardized that could do something like blur/glass effects behind windows here.

@haudan
Copy link
Author

haudan commented Jun 1, 2018

@francesca64 thanks for the help!

So I started with the MacOS backend, which was easy enough to get going; simply subclassing WinitView from NSVisualEffectView was enough to get some simple blur. However, now I'm running into a problem when I try to set the NSVisualEffectView properties of WinitView:

if win_attribs.blur {
    use objc::Message;

    // This line is ok, it doesn't panic.
    (*view).verify_message::<(i64,), ()>(sel!(setMaterial:)).unwrap();

    // This line causes a segfault inside [NSView isHiddenOrHasHiddenAncestor],
    // for some reason. 2i64 is the constant for NSVisualEffectView.Material.dark.
    let _: () = msg_send![view, setMaterial: 2i64];
}

I'm calling this right after this line.


Nevermind, found the issue (even before submitting this comment): I was supposed to call initWithWinit before setMaterial. I'm submitting this comment anyway to forever remind myself how I wasted 3-4 hours of my life by writing and debugging a test application in swift and comparing the swiftc generated assembler code with rustc's, as well as trying out every combination of objc-message passing and ivar writing possible on this earth. But hey, at least now I know how to use lldb on the command line.

@OvermindDL1
Copy link

Nevermind, found the issue (even before submitting this comment): I was supposed to call initWithWinit before setMaterial. I'm submitting this comment anyway to forever remind myself how I wasted 3-4 hours of my life by writing and debugging a test application in swift and comparing the swiftc generated assembler code with rustc's, as well as trying out every combination of objc-message passing and ivar writing possible on this earth. But hey, at least now I know how to use lldb on the command line.

Lol, we've all been there. ^.^

@francesca64
Copy link
Member

Yeah, the Obj-C pattern of calling alloc and then init is something that surprised me in the beginning, since it's just so unergonomic (some classes have new, which does both for you in one step, but that pattern is heavily discouraged by Apple). alloc is basically the equivalent of mem::uninitialized, as you've discovered the hard way.

Anyway, good dedication! There's a wide variety of errors you can encounter when interfacing with Obj-C, including some I've never seen outside of doing that, i.e. bus error 10. If you look into the generated Apple bug report, it can sometimes contain more helpful details than you'd get otherwise.

@haudan
Copy link
Author

haudan commented Jun 15, 2018

A little progress update:
Image

Should I create a pull request now that I have a working MacOS implementation, or should I wait until I'm done with the other backends as well? I'd like to create it now for code review, so that I don't repeat mistakes.

@francesca64
Copy link
Member

Looks nice! Feel free to create a PR, and I'll review it.

@filnet
Copy link
Contributor

filnet commented Feb 1, 2020

Looks like this issue could be closed.

@goddessfreya
Copy link
Contributor

@filnet Where was Glassy windows implemented? #568 was closed cause it got stale, and I don't know of any other PRs implementing it.

@filnet
Copy link
Contributor

filnet commented Feb 2, 2020

@goddessfreya I got it wrong. Sorry.

@goddessfreya
Copy link
Contributor

No worries, @filnet.

@haudan
Copy link
Author

haudan commented Apr 18, 2023

5 years and I'm back. Can anyone bring me up to date on the state of things? Should the issue be closed? The PR probably should be re-coded from scratch.

@kchibisov
Copy link
Member

Likely re-coded from scratch, but the issue on its own is pretty simple to be fair.

@dsseng
Copy link
Contributor

dsseng commented Aug 24, 2023

Working on supporting KDE blur protocol. Will this be merge-able if the only supported environment so far is KDE Wayland? KDE X11 can probably be added as well, will see later.

image

@kchibisov
Copy link
Member

@sh7dm I think the main issue why it's not added is that the protocol is not standard. I remember asking about it in the past to propose it upstream, but to no avail. I remember KDE devs said that the protocol itself needed some work, but what exactly was missing I don't remember.

The other part of the issue is to bring something that can work cross platform, on Wayland we set a bunch of rectangles, but it's not clear when they invalidate, etc. How to map them to e.g. macOS, Windows, etc.

@dsseng
Copy link
Contributor

dsseng commented Aug 24, 2023

On KDE I just submit the surface to be blurred. From other DEs I know GNOME extensions that blur everything and Hyprland probably does that as well. Windows and macOS probably also have a flag to be flipped for alpha backgrounds to be blurred. No rectangle manipulation is done in my case.

@kchibisov
Copy link
Member

On KDE you mark regions to be blurred, it's not just one surface iirc.

@dsseng
Copy link
Contributor

dsseng commented Aug 24, 2023

On KDE you mark regions to be blurred, it's not just one surface iirc.

You can, but it's optional. I do full window as probably expected. Those who want regions can use raw-window-handle

@kchibisov
Copy link
Member

@sh7dm creating a queue in the client just to overcome winit limitations sounds like a bad design to me. Nothing stops to have regions correctly supported.

dsseng added a commit to dsseng/winit that referenced this issue Aug 28, 2023
@dsseng
Copy link
Contributor

dsseng commented Aug 28, 2023

@kchibisov neither macOS nor Windows seem to support partial blurring, so I avoided adding a KWin-specific feature with doubted usefulness (per-region blurring)

dsseng added a commit to dsseng/winit that referenced this issue Aug 28, 2023
@kchibisov
Copy link
Member

Well, we could go without partial bluring for now then.

dsseng added a commit to dsseng/winit that referenced this issue Oct 8, 2023
Related to rust-windowing#538

address review comments
dsseng added a commit to dsseng/winit that referenced this issue Oct 8, 2023
Related to rust-windowing#538

address review comments
dsseng added a commit to dsseng/winit that referenced this issue Oct 8, 2023
Related to rust-windowing#538

address review comments
@kchibisov
Copy link
Member

Window::set_blur was added, but only implemented on Wayland.

@kchibisov kchibisov added DS - macos DS - x11 and removed D - hard Likely harder than most tasks here P - normal Great to have C - needs discussion Direction must be ironed out labels Oct 8, 2023
@dsseng
Copy link
Contributor

dsseng commented Oct 8, 2023

* KWin only, other compositors don't seem to feature standardized blur management protocol

@MarijnS95
Copy link
Member

For future reference, Windows Mica/Acrylic (two forms of background blurring, consistent with other themed apps) have been exposed in Winit in #3257.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
DS - macos DS - windows DS - x11 H - help wanted Someone please save us S - enhancement Wouldn't this be the coolest?
Development

No branches or pull requests

8 participants