diff --git a/NickvisionCavalier.GNOME/Blueprints/drawing_view.blp b/NickvisionCavalier.GNOME/Blueprints/drawing_view.blp index 8750335..f1dea3f 100644 --- a/NickvisionCavalier.GNOME/Blueprints/drawing_view.blp +++ b/NickvisionCavalier.GNOME/Blueprints/drawing_view.blp @@ -23,4 +23,12 @@ Gtk.Stack _root { auto-render: false; }; } + + Gtk.StackPage _cairoPage { + name: "cairo"; + child: Gtk.DrawingArea _cairoArea { + hexpand: true; + vexpand: true; + }; + } } \ No newline at end of file diff --git a/NickvisionCavalier.GNOME/Program.cs b/NickvisionCavalier.GNOME/Program.cs index 5a81ce9..812b280 100644 --- a/NickvisionCavalier.GNOME/Program.cs +++ b/NickvisionCavalier.GNOME/Program.cs @@ -34,13 +34,7 @@ public Program(string[] args) _mainWindow = null; _mainWindowController = new MainWindowController(args); _mainWindowController.AppInfo.Changelog = - @"* Cavalier can now be controlled from command line. Run the app with --help option to see full list of available options - * Reverse mirror option is now available with full mirror - * It's now possible to set frames per second to 144 or to a custom value - * Added anti-aliasing, so rounded items now look less pixelated - * Added ability to set background image - * New drawing mode - Splitter - * Bars limit was increased to 100 + @"* Added Cairo backend that can be used in case of problems with OpenGL. To activate, run the program with environment variable CAVALIER_RENDERER=cairo * Updated translations (Thanks everyone on Weblate!)"; _application.OnActivate += OnActivate; if (File.Exists(Path.GetFullPath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)) + "/org.nickvision.cavalier.gresource")) diff --git a/NickvisionCavalier.GNOME/Views/DrawingView.cs b/NickvisionCavalier.GNOME/Views/DrawingView.cs index d862ab3..9bde7e6 100644 --- a/NickvisionCavalier.GNOME/Views/DrawingView.cs +++ b/NickvisionCavalier.GNOME/Views/DrawingView.cs @@ -20,14 +20,17 @@ public partial class DrawingView : Gtk.Stack, IDisposable private static partial void glClear(uint mask); [Gtk.Connect] private readonly Gtk.GLArea _glArea; + [Gtk.Connect] private readonly Gtk.DrawingArea _cairoArea; private bool _disposed; private readonly DrawingViewController _controller; + private readonly bool _useCairo; private readonly GSourceFunc _showGl; private readonly GSourceFunc _queueRender; private readonly Timer _renderTimer; private GRContext? _ctx; private SKSurface? _glSurface; + private Cairo.ImageSurface? _cairoSurface; private SKSurface? _skSurface; private float[]? _sample; @@ -37,33 +40,50 @@ private DrawingView(Gtk.Builder builder, DrawingViewController controller) : bas _controller = controller; //Build UI builder.Connect(this); - _glArea.OnRealize += (sender, e) => + if (Environment.GetEnvironmentVariable("CAVALIER_RENDERER")?.ToLower() == "cairo") { - _glArea.MakeCurrent(); - var grInt = GRGlInterface.Create(eglGetProcAddress); - _ctx = GRContext.CreateGl(grInt); - }; - _glArea.OnResize += (sender, e) => CreateSurface(); + _useCairo = true; + _cairoArea.OnResize += (sender, e) => CreateCairoSurface(); + _cairoArea.SetDrawFunc(CairoDrawFunc); + } + else + { + _useCairo = false; + _glArea.OnRealize += (sender, e) => + { + _glArea.MakeCurrent(); + var grInt = GRGlInterface.Create(eglGetProcAddress); + _ctx = GRContext.CreateGl(grInt); + }; + _glArea.OnResize += (sender, e) => CreateGLSurface(); + _glArea.OnRender += OnRender; + } _controller.CAVA.OutputReceived += (sender, sample) => { _sample = sample; GLib.Functions.IdleAdd(0, () => { - if (GetVisibleChildName() != "gl") + if (GetVisibleChildName() != (_useCairo ? "cairo" : "gl")) { - SetVisibleChildName("gl"); + SetVisibleChildName(_useCairo ? "cairo" : "gl"); } return false; }); }; - _glArea.OnRender += OnRender; _renderTimer = new Timer(1000.0 / _controller.Framerate); _renderTimer.Elapsed += (sender, e) => { _renderTimer.Interval = 1000.0 / _controller.Framerate; GLib.Functions.IdleAdd(0, () => { - _glArea.QueueRender(); + if (_useCairo) + { + _cairoArea.QueueDraw(); + } + else + { + _glArea.QueueRender(); + } return false; }); }; @@ -86,7 +106,7 @@ public DrawingView(DrawingViewController controller) : this(Builder.FromFile("dr /// /// Frees resources used by the DrawingView object /// - public void Dispose() + public new void Dispose() { Dispose(true); GC.SuppressFinalize(this); @@ -109,9 +129,9 @@ protected virtual void Dispose(bool disposing) } /// - /// (Re)creates drawing surface + /// (Re)creates drawing surface when using OpenGL /// - private void CreateSurface() + private void CreateGLSurface() { _glSurface?.Dispose(); _skSurface?.Dispose(); @@ -124,9 +144,27 @@ private void CreateSurface() } } + /// + /// (Re)creates drawing surface when using Cairo + /// + private void CreateCairoSurface() + { + _skSurface?.Dispose(); + var imgInfo = new SKImageInfo(_cairoArea.GetAllocatedWidth(), _cairoArea.GetAllocatedHeight()); + _cairoSurface = new Cairo.ImageSurface(Cairo.Format.Argb32, imgInfo.Width, imgInfo.Height); + if (_cairoSurface != null) + { + _skSurface = SKSurface.Create(imgInfo, Cairo.Internal.ImageSurface.GetData(_cairoSurface.Handle), imgInfo.RowBytes); + _controller.Canvas = _skSurface.Canvas; + } + } + /// /// Occurs on GLArea render frames /// + /// GLArea + /// EventArgs + /// Whether or not the event was handled private bool OnRender(Gtk.GLArea sender, EventArgs e) { if (_skSurface == null) @@ -146,6 +184,29 @@ private bool OnRender(Gtk.GLArea sender, EventArgs e) return false; } + /// + /// Occurs when DrawingArea should be redrawn + /// + /// DrawingArea + /// Cairo context of the DrawingArea + /// Area width + /// Area height + public void CairoDrawFunc(Gtk.DrawingArea area, Cairo.Context ctx, int width, int height) + { + if (_skSurface == null) + { + return; + } + if (_sample != null) + { + _controller.Render(_sample, (float)width, (float)height); + _cairoSurface!.Flush(); + _cairoSurface.MarkDirty(); + ctx.SetSourceSurface(_cairoSurface, 0, 0); + ctx.Paint(); + } + } + /// /// Occurs when settings for CAVA have changed /// diff --git a/NickvisionCavalier.Shared/Controllers/MainWindowController.cs b/NickvisionCavalier.Shared/Controllers/MainWindowController.cs index f7f2389..5bf6aae 100644 --- a/NickvisionCavalier.Shared/Controllers/MainWindowController.cs +++ b/NickvisionCavalier.Shared/Controllers/MainWindowController.cs @@ -60,7 +60,7 @@ public MainWindowController(string[] args) { Aura = new Aura("org.nickvision.cavalier", "Nickvision Cavalier", _("Cavalier"), _("Visualize audio with CAVA")); Aura.Active.SetConfig("config"); - AppInfo.Version = "2023.8.0"; + AppInfo.Version = "2023.8.1-next"; AppInfo.SourceRepo = new Uri("https://github.com/NickvisionApps/Cavalier"); AppInfo.IssueTracker = new Uri("https://github.com/NickvisionApps/Cavalier/issues/new"); AppInfo.SupportUrl = new Uri("https://github.com/NickvisionApps/Cavalier/discussions"); diff --git a/NickvisionCavalier.Shared/org.nickvision.cavalier.metainfo.xml.in b/NickvisionCavalier.Shared/org.nickvision.cavalier.metainfo.xml.in index 28a3d07..2c79060 100644 --- a/NickvisionCavalier.Shared/org.nickvision.cavalier.metainfo.xml.in +++ b/NickvisionCavalier.Shared/org.nickvision.cavalier.metainfo.xml.in @@ -35,17 +35,11 @@ - +

New Cavalier!

    -
  • Cavalier can now be controlled from command line. Run the app with --help option to see full list of available options
  • -
  • Reverse mirror option is now available with full mirror
  • -
  • It's now possible to set frames per second to 144 or to a custom value
  • -
  • Added anti-aliasing, so rounded items now look less pixelated
  • -
  • Added ability to set background image
  • -
  • New drawing mode - Splitter
  • -
  • Bars limit was increased to 100
  • +
  • Added Cairo backend that can be used in case of problems with OpenGL. To activate, run the program with environment variable CAVALIER_RENDERER=cairo
  • Updated translations (Thanks everyone on Weblate!)