diff --git a/Terminal.Gui/Drawing/SixelSupportDetector.cs b/Terminal.Gui/Drawing/SixelSupportDetector.cs index 9254a9605..4713d5e25 100644 --- a/Terminal.Gui/Drawing/SixelSupportDetector.cs +++ b/Terminal.Gui/Drawing/SixelSupportDetector.cs @@ -1,5 +1,4 @@ using System.Text.RegularExpressions; -using Microsoft.CodeAnalysis; namespace Terminal.Gui; @@ -20,68 +19,115 @@ public class SixelSupportDetector { var result = new SixelSupportResult (); - result.IsSupported = - AnsiEscapeSequenceRequest.TryExecuteAnsiRequest (EscSeqUtils.CSI_SendDeviceAttributes, out AnsiEscapeSequenceResponse darResponse) - ? darResponse.Response.Split (';').Contains ("4") - : false; + result.IsSupported = IsSixelSupportedByDar (); if (result.IsSupported) { - // Expect something like: - //[6;20;10t - - bool gotResolutionDirectly = false; - - if (AnsiEscapeSequenceRequest.TryExecuteAnsiRequest (EscSeqUtils.CSI_RequestSixelResolution, out var resolution)) + if (TryGetResolutionDirectly (out var res)) { - // Terminal supports directly responding with resolution - var match = Regex.Match (resolution.Response, @"\[\d+;(\d+);(\d+)t$"); - - if (match.Success) - { - if (int.TryParse (match.Groups [1].Value, out var ry) && - int.TryParse (match.Groups [2].Value, out var rx)) - { - result.Resolution = new Size (rx, ry); - gotResolutionDirectly = true; - } - } + result.Resolution = res; + } + else if(TryComputeResolution(out res)) + { + result.Resolution = res; } - if (!gotResolutionDirectly) - { - // Fallback to window size in pixels and characters - if (AnsiEscapeSequenceRequest.TryExecuteAnsiRequest (EscSeqUtils.CSI_RequestWindowSizeInPixels, out var pixelSizeResponse) && - AnsiEscapeSequenceRequest.TryExecuteAnsiRequest (EscSeqUtils.CSI_ReportTerminalSizeInChars, out var charSizeResponse)) - { - // Example [4;600;1200t - var pixelMatch = Regex.Match (pixelSizeResponse.Response, @"\[\d+;(\d+);(\d+)t$"); - - // Example [8;30;120t - var charMatch = Regex.Match (charSizeResponse.Response, @"\[\d+;(\d+);(\d+)t$"); - - if (pixelMatch.Success && charMatch.Success) - { - // Extract pixel dimensions - if (int.TryParse (pixelMatch.Groups [1].Value, out var pixelHeight) && - int.TryParse (pixelMatch.Groups [2].Value, out var pixelWidth) && - // Extract character dimensions - int.TryParse (charMatch.Groups [1].Value, out var charHeight) && - int.TryParse (charMatch.Groups [2].Value, out var charWidth) && - charWidth != 0 && charHeight != 0) // Avoid divide by zero - { - // Calculate the character cell size in pixels - var cellWidth = (int)Math.Round ((double)pixelWidth / charWidth); - var cellHeight = (int)Math.Round ((double)pixelHeight / charHeight); - - // Set the resolution based on the character cell size - result.Resolution = new Size (cellWidth, cellHeight); - } - } - } - } + result.SupportsTransparency = IsWindowsTerminal () || IsXtermWithTransparency (); } return result; } + + + private bool TryGetResolutionDirectly (out Size resolution) + { + // Expect something like: + //[6;20;10t + + if (AnsiEscapeSequenceRequest.TryExecuteAnsiRequest (EscSeqUtils.CSI_RequestSixelResolution, out var response)) + { + // Terminal supports directly responding with resolution + var match = Regex.Match (response.Response, @"\[\d+;(\d+);(\d+)t$"); + + if (match.Success) + { + if (int.TryParse (match.Groups [1].Value, out var ry) && + int.TryParse (match.Groups [2].Value, out var rx)) + { + resolution = new Size (rx, ry); + + return true; + } + } + } + + resolution = default; + return false; + } + + + private bool TryComputeResolution (out Size resolution) + { + // Fallback to window size in pixels and characters + if (AnsiEscapeSequenceRequest.TryExecuteAnsiRequest (EscSeqUtils.CSI_RequestWindowSizeInPixels, out var pixelSizeResponse) + && AnsiEscapeSequenceRequest.TryExecuteAnsiRequest (EscSeqUtils.CSI_ReportTerminalSizeInChars, out var charSizeResponse)) + { + // Example [4;600;1200t + var pixelMatch = Regex.Match (pixelSizeResponse.Response, @"\[\d+;(\d+);(\d+)t$"); + + // Example [8;30;120t + var charMatch = Regex.Match (charSizeResponse.Response, @"\[\d+;(\d+);(\d+)t$"); + + if (pixelMatch.Success && charMatch.Success) + { + // Extract pixel dimensions + if (int.TryParse (pixelMatch.Groups [1].Value, out var pixelHeight) + && int.TryParse (pixelMatch.Groups [2].Value, out var pixelWidth) + && + + // Extract character dimensions + int.TryParse (charMatch.Groups [1].Value, out var charHeight) + && int.TryParse (charMatch.Groups [2].Value, out var charWidth) + && charWidth != 0 + && charHeight != 0) // Avoid divide by zero + { + // Calculate the character cell size in pixels + var cellWidth = (int)Math.Round ((double)pixelWidth / charWidth); + var cellHeight = (int)Math.Round ((double)pixelHeight / charHeight); + + // Set the resolution based on the character cell size + resolution = new Size (cellWidth, cellHeight); + + return true; + } + } + } + + resolution = default; + return false; + } + private bool IsSixelSupportedByDar () + { + return AnsiEscapeSequenceRequest.TryExecuteAnsiRequest (EscSeqUtils.CSI_SendDeviceAttributes, out AnsiEscapeSequenceResponse darResponse) + ? darResponse.Response.Split (';').Contains ("4") + : false; + } + + private bool IsWindowsTerminal () + { + return !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable ("WT_SESSION"));; + } + private bool IsXtermWithTransparency () + { + // Check if running in real xterm (XTERM_VERSION is more reliable than TERM) + var xtermVersionStr = Environment.GetEnvironmentVariable ("XTERM_VERSION"); + + // If XTERM_VERSION exists, we are in a real xterm + if (!string.IsNullOrWhiteSpace (xtermVersionStr) && int.TryParse (xtermVersionStr, out var xtermVersion) && xtermVersion >= 370) + { + return true; + } + + return false; + } } \ No newline at end of file diff --git a/Terminal.Gui/Drawing/SixelSupportResult.cs b/Terminal.Gui/Drawing/SixelSupportResult.cs index d9b8eb03e..db42ad237 100644 --- a/Terminal.Gui/Drawing/SixelSupportResult.cs +++ b/Terminal.Gui/Drawing/SixelSupportResult.cs @@ -8,7 +8,7 @@ public class SixelSupportResult { /// - /// Whether the current driver supports sixel graphic format. + /// Whether the terminal supports sixel graphic format. /// Defaults to false. /// public bool IsSupported { get; set; } @@ -24,4 +24,10 @@ public class SixelSupportResult /// to 256. /// public int MaxPaletteColors { get; set; } = 256; + + /// + /// Whether the terminal supports transparent background sixels. + /// Defaults to false + /// + public bool SupportsTransparency { get; set; } }