Avalonia icon indicating copy to clipboard operation
Avalonia copied to clipboard

Make content nonclickable in Transparent Window

Open FG-rgb opened this issue 4 years ago • 25 comments

In WPF, a Window with AllowsTransparency="True" and a Transparent Background has a special behavior I'm missing in Avalonia: If you click on a fully transparent Area of the Window, the click is not handled by this window and goes "through" it, like there is a hole in it. Is it possible and crossplatform conform to implement this behavior?

My use case is to show a Window/Rectangle with only a red border, at a special position, to use as a "marker"/"hint". Actually, if I set SystemDecorations = SystemDecorations.None and TransparencyLevelHint = WindowTransparencyLevel.Transparent, like described in https://github.com/AvaloniaUI/Avalonia/issues/2306 the window is still clickable.

FG-rgb avatar Oct 28 '20 14:10 FG-rgb

Probably doable via SetWindowRgn on Win32 and XShape extension on Linux. Not quite sure about macOS

kekekeks avatar Oct 28 '20 14:10 kekekeks

Okay, I've managed to use CombineRgn in combination with SetWindowRgn. This is a working solution. But I've got problems to get native window positions from avalonia window. It seems that the location/size differs a bit, or I have a calculation bug in my code. Is there a best practise to get native screen position and size for the avalonia window?

FG-rgb avatar Nov 02 '20 10:11 FG-rgb

I've re-checked my code. My calculation is correct, but what I found: Window.Position seems NOT to be the position on the screen! How can I get the avalonia window position/location of the screen?

FG-rgb avatar Nov 02 '20 15:11 FG-rgb

And how can I convert screen coordinates to avalonia window position values?

FG-rgb avatar Nov 02 '20 15:11 FG-rgb

Window.Position seems NOT to be the position on the screen

Excuse me, what? Window.Position is returning the value from IWindowImpl.Position. Win32 implementation of that property calls GetWindowRect and takes the coordinate of the upper-left corner.

Those coordinates are in pixel coordinate space.

kekekeks avatar Nov 02 '20 18:11 kekekeks

Ok, it seems that the position I'm getting is correct, but if I set a position using Window.Position it behaves strange. Sorry, I don't want to be unfair. You all doing a great job. Big thanks. I will retest and check what's exactly the cause of it.

FG-rgb avatar Nov 03 '20 09:11 FG-rgb

I re-read the documentation of CreateRectRgn and found out that it is working with logical units, and not with pixels. This seem to be the problem. Sorry for complain here.

FG-rgb avatar Nov 03 '20 10:11 FG-rgb

CreateRectRgn should operate in window coordinate space with (0, 0) being the top-left corner of the window

kekekeks avatar Nov 03 '20 15:11 kekekeks

I actually don't get it to work properly. Every time I do a step forward I have to get one or two back... I have a WPF overlay window, to let the user do some decisions for recording, that is working properly. Now I'm migrating it to avalonia, which is wonderful to work with. But this kind of clipping transparent areas makes me headaches.

In full screen mode, clipping a simple rectangle seem to work, but If I resize the window or change the position it behaves strange. It's like the position is exponental shifted, or scaled by something I didn't get...

FG-rgb avatar Nov 03 '20 15:11 FG-rgb

I will re-use my old WPF code, until avalonia supports it, or I have another idea.

FG-rgb avatar Nov 03 '20 17:11 FG-rgb

This workaround using MonoMac works on macOS:

// this = Avalonia.Controls.Window
if (this.PlatformImpl.Handle is IMacOSTopLevelPlatformHandle macosHandle) {
    MonoMac.AppKit.NSApplication.Init();
    var nsWindow = (MonoMac.AppKit.NSWindow) MonoMac.ObjCRuntime.Runtime.GetNSObject(macosHandle.NSWindow);
    nsWindow.IgnoresMouseEvents = true;
}

jjaksic avatar Feb 24 '21 21:02 jjaksic

Is there the same simple code for linux as for macOS?

07artem132 avatar Jul 11 '21 16:07 07artem132

Is there the same simple code for linux as for macOS?

Or a working solution for Windows?

FG-rgb avatar Jul 12 '21 07:07 FG-rgb

Is there the same simple code for linux as for macOS?

Or a working solution for Windows?

for windows this will help you https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-nchittest and https://github.com/AvaloniaUI/Avalonia/blob/b00144eacd1a61c4ec7cb7d13aadd94c5f995ba9/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs#L416

07artem132 avatar Jul 12 '21 15:07 07artem132

Is there the same simple code for linux as for macOS?

Or a working solution for Windows?

for windows this will help you https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-nchittest and

https://github.com/AvaloniaUI/Avalonia/blob/b00144eacd1a61c4ec7cb7d13aadd94c5f995ba9/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs#L416

How can I override WndProc to always return HTTRANSPARENT?

FG-rgb avatar Aug 03 '21 14:08 FG-rgb

I want to know, too?

3400442579 avatar Aug 06 '21 02:08 3400442579

The Problem is... to show a rectangle it would be a workaround to use 4 Windows and position them... but the next problem than would be that a window have a fixed minWidth of 50 Pixels Width?! So I would need a workaround for a workaround. I see a lack of feature here.

FG-rgb avatar Aug 06 '21 07:08 FG-rgb

I have a similar issue, I am porting an application which has a window overlay which shows ingame notifications, using the WPF AllowTransparency=True and SetWindowLong(Handle, GWL_EXSTYLE, Style | WS_EX_TRANSPARENT) every component on the window which is basically the notification toast usercontrol is not clickable, which means that every click is passed to the main game window which is what i'm trying to do with avalonia with no success, I tried adding WS_EX_LAYERED to SetWindowLong but with that the window doesn't appear at all. If someone can explain how to apply this clickthrough property to an avalonia window i'll be very grateful.

Edit: nvm, i was able to do that by using:


            SetWindowLong(this.PlatformImpl.Handle.Handle, GWL_EXSTYLE, Style | WS_EX_LAYERED | WS_EX_TRANSPARENT)
            SetLayeredWindowAttributes(this.PlatformImpl.Handle.Handle, 0, 255, 0x2);

leoaviana avatar Aug 14 '21 23:08 leoaviana

Edit: nvm, i was able to do that by using:


            SetWindowLong(this.PlatformImpl.Handle.Handle, GWL_EXSTYLE, Style | WS_EX_LAYERED | WS_EX_TRANSPARENT)
            SetLayeredWindowAttributes(this.PlatformImpl.Handle.Handle, 0, 255, 0x2);

BINGO! That's a workaround which resolves it in case of OS Platform is Windows! Big Thanks.

FG-rgb avatar Aug 26 '21 12:08 FG-rgb

@FG-rgb Do you know if it's possible to make some of the controls clickable? I am also porting a project from WPF to Avalonia and I need to create a transparent Window where the notification buttons are clickable.

Jasonvb avatar Dec 06 '21 12:12 Jasonvb

@FG-rgb Do you know if it's possible to make some of the controls clickable? I am also porting a project from WPF to Avalonia and I need to create a transparent Window where the notification buttons are clickable.

@Jasonvb You can try the approach described by @kekekeks

FG-rgb avatar Dec 06 '21 12:12 FG-rgb

@FG-rgb I am searching for a cross platform solution.

Jasonvb avatar Dec 06 '21 14:12 Jasonvb

By the way, I am thinking of creating a seperate Window (only containing the notification itself) for each of the notifications instead of creating one overlay for all notifications. In my application there could be multiple notifications shown at the same time. Is this a good idea or will I get in trouble with setting multiple notification windows topmost=True?

Jasonvb avatar Dec 06 '21 14:12 Jasonvb

There shouldn't be any problems, but you obviously will have less control over notifications, if you want controls to visually interact with each other, like animations.

maxkatz6 avatar Dec 08 '21 07:12 maxkatz6

Is there any currently available solution? It seems that MonoMac.AppKit is no longer functional.

ParaN3xus avatar Jul 13 '23 08:07 ParaN3xus