Skip to content

Support Window transparency #2762

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

Merged
merged 1 commit into from
Mar 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 65 additions & 4 deletions src/Eto.Gtk/Forms/GtkWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -336,9 +336,12 @@ public bool MovableByWindowBackground
if (Widget.Properties.TrySet(GtkWindow.MovableByWindowBackground_Key, value))
{
if (value)
Control.ButtonPressEvent += Connector.ButtonPressEvent_Movable;
{
containerBox.AddEvents((int)Gdk.EventMask.ButtonPressMask);
containerBox.ButtonPressEvent += Connector.ButtonPressEvent_Movable;
}
else
Control.ButtonPressEvent -= Connector.ButtonPressEvent_Movable;
containerBox.ButtonPressEvent -= Connector.ButtonPressEvent_Movable;
}
}
}
Expand Down Expand Up @@ -547,11 +550,36 @@ internal void ButtonPressEvent_Movable(object o, Gtk.ButtonPressEventArgs args)
if (handler == null)
return;
var evt = args.Event;
if (handler != null && evt.Type == Gdk.EventType.ButtonPress && evt.Button == 1)
{
if (!Equals(args.RetVal, true) && evt.Type == Gdk.EventType.ButtonPress && evt.Button == 1)
{
handler.Control.BeginMoveDrag((int)evt.Button, (int)evt.XRoot, (int)evt.YRoot, evt.Time);
args.RetVal = true;
}
}

[GLib.ConnectBefore]
internal void HandleDrawnEvent(object o, Gtk.DrawnArgs args)
{
var handler = Handler;
if (handler == null)
return;
// use cairo to draw the background color with alpha
var cr = args.Cr;
var color = handler.BackgroundColor;
cr.Save();
if (color.A > 0)
{
cr.SetSourceRGBA(color.R, color.G, color.B, color.A);
cr.Operator = Cairo.Operator.Source;
}
else
{
cr.Operator = Cairo.Operator.Clear;
}
cr.Paint();
cr.Restore();
}

}

public MenuBar Menu
Expand Down Expand Up @@ -925,5 +953,38 @@ public override void InvalidateMeasure()
Application.Instance.AsyncInvoke(PerformResize);
}
}

public override Gtk.Widget BackgroundControl => Control;

bool isDrawingBackground;

protected override void SetBackgroundColor(Color? color)
{
if (color?.A < 1 || isDrawingBackground)
{
if (!isDrawingBackground)
{
Control.AppPaintable = true;
var screen = Gdk.Screen.Default;
var visual = screen.RgbaVisual;

if (visual != null && screen.IsComposited)
Control.Visual = visual;

Control.Drawn -= Connector.HandleDrawnEvent;
Control.Drawn += Connector.HandleDrawnEvent;
isDrawingBackground = true;
base.SetBackgroundColor(null);
}

Control.QueueDraw();
}
else
{
Control.AppPaintable = false;
Control.Drawn -= Connector.HandleDrawnEvent;
base.SetBackgroundColor(color);
}
}
}
}
5 changes: 5 additions & 0 deletions src/Eto.Mac/Forms/MacWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,11 @@ public bool MovableByWindowBackground

protected override Color DefaultBackgroundColor => NSColor.WindowBackground.ToEtoWithAppearance();

protected override void SetBackgroundColor(Color? color)
{
Control.BackgroundColor = (color ?? DefaultBackgroundColor).ToNSUI();
}

protected override SizeF GetNaturalSize(SizeF availableSize)
{
SizeF naturalSize = new SizeF(200, 200);
Expand Down
6 changes: 4 additions & 2 deletions src/Eto.WinForms/Forms/WindowsControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -662,13 +662,15 @@ public virtual Color BackgroundColor
set
{
backgroundColorSet = true;
var color = value.ToSD();
try
{
Control.BackColor = value.ToSD();
Control.BackColor = color;
}
catch
{
// some controls don't support transparent colors, ignore..
// some controls don't support transparent colors, set only RGB..
Control.BackColor = sd.Color.FromArgb(255, color);
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/Eto.WinForms/Win32.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,10 @@ public enum WS : uint
public enum WS_EX : uint
{
TOPMOST = 0x00000008,
TRANSPARENT = 0x00000020,
TOOLWINDOW = 0x00000080,
APPWINDOW = 0x00040000,
LAYERED = 0x00080000,
NOACTIVATE = 0x08000000
}

Expand Down
49 changes: 37 additions & 12 deletions src/Eto.Wpf/Forms/WpfWindow.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Eto.Wpf.CustomControls;
using Eto.Wpf.Forms.Menu;
using Eto.Wpf.Drawing;
using System.Windows.Input;

namespace Eto.Wpf.Forms
{
Expand Down Expand Up @@ -84,22 +85,23 @@ public bool MovableByWindowBackground
{
if (Widget.Properties.TrySet(WpfWindow.MovableByWindowBackground_Key, value))
{
if (value)
content.MouseLeftButtonDown += Content_MouseLeftButtonDown;
else
content.MouseLeftButtonDown -= Content_MouseLeftButtonDown;
HandleEvent(Eto.Forms.Control.MouseDownEvent);
}
}
}

void Content_MouseLeftButtonDown(object sender, swi.MouseButtonEventArgs e)
protected override void HandleMouseDown(object sender, MouseButtonEventArgs e)
{
// mouse could be captured by something else, so we release it here to ensure the DragMove works.
// we only get here if no control has handled the mouse down event.
swi.Mouse.Captured?.ReleaseMouseCapture();
base.HandleMouseDown(sender, e);
if (!e.Handled && MovableByWindowBackground && e.GetEtoButtons() == MouseButtons.Primary)
{
// mouse could be captured by something else, so we release it here to ensure the DragMove works.
// we only get here if no control has handled the mouse down event.
swi.Mouse.Captured?.ReleaseMouseCapture();

Control.DragMove();
e.Handled = true;
Control.DragMove();
e.Handled = true;
}
}

protected override void Initialize()
Expand Down Expand Up @@ -955,8 +957,15 @@ public WindowStyle WindowStyle
{
if (WindowStyle != value)
{
if (isSourceInitialized && Control.AllowsTransparency)
{
Trace.WriteLine("WARNING: Changing window style after window is shown is not supported on this platform");
return;
}

Control.WindowStyle = value.ToWpf();
SetWindowChrome();
SetWindowTransparency();
}
}
}
Expand Down Expand Up @@ -1043,8 +1052,24 @@ public void SendToBack()

public override Color BackgroundColor
{
get { return content.Background.ToEtoColor(); }
set { content.Background = value.ToWpfBrush(content.Background); }
get => (Control.Background ?? sw.SystemColors.ControlBrush).ToEtoColor();
set
{
Control.Background = value.ToWpfBrush();
SetWindowTransparency();
}
}

void SetWindowTransparency()
{
var isTransparent = Control.Background is swm.SolidColorBrush scb && scb.Color.A < 255 && WindowStyle == WindowStyle.None;
if (isSourceInitialized)
{
if (isTransparent != Control.AllowsTransparency)
Trace.WriteLine("WARNING: Changing transparency after window is shown is not supported on this platform");
return;
}
Control.AllowsTransparency = isTransparent;
}

public Screen Screen
Expand Down
5 changes: 4 additions & 1 deletion src/Eto.Wpf/themes/controls/Window.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
xmlns:ef="clr-namespace:Eto.Wpf.Forms"
xmlns:s="clr-namespace:System;assembly=mscorlib">

<Style TargetType="ef:EtoWindowContent">
<Style TargetType="ef:EtoFormWindow">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
</Style>
<Style TargetType="ef:EtoWindow">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
</Style>

Expand Down
Empty file modified test/Eto.Test.Wpf/Eto.Test.Wpf.csproj
100644 → 100755
Empty file.
Empty file modified test/Eto.Test.Wpf/Startup.cs
100644 → 100755
Empty file.
Loading
Loading