Skip to content

Commit

Permalink
docs(CTK): commit for merge conflict fix applyed
Browse files Browse the repository at this point in the history
  • Loading branch information
DevTKSS committed Jan 7, 2025
2 parents a92363f + f01ac40 commit 0265ec4
Show file tree
Hide file tree
Showing 29 changed files with 1,259 additions and 636 deletions.
2 changes: 1 addition & 1 deletion src/Uno.UI.Runtime.Skia.Gtk/Helpers/Dpi/DpiHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Uno.UI.Runtime.Skia.Gtk.Helpers.Dpi;

internal class DpiHelper
{
private readonly StartStopEventWrapper<EventHandler> _dpiChangedWrapper;
private readonly StartStopDelegateWrapper<EventHandler> _dpiChangedWrapper;
private readonly UnoGtkWindow _window;

private float? _dpi;
Expand Down
10 changes: 7 additions & 3 deletions src/Uno.UI.Runtime.Skia.X11/X11ApplicationHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ namespace Uno.WinUI.Runtime.Skia.X11;
public partial class X11ApplicationHost : SkiaHost, ISkiaApplicationHost, IDisposable
{
[ThreadStatic] private static bool _isDispatcherThread;
[ThreadStatic] private static int _renderFrameRate;
private readonly EventLoop _eventLoop;

private readonly Func<Application> _appBuilder;
Expand Down Expand Up @@ -75,19 +74,24 @@ public X11ApplicationHost(Func<Application> appBuilder, int renderFrameRate = 60
{
_appBuilder = appBuilder;

if (RenderFrameRate != default && renderFrameRate != RenderFrameRate)
{
throw new InvalidOperationException($"X11's render frame rate should only be set once.");
}
RenderFrameRate = renderFrameRate;

_eventLoop = new EventLoop();
_eventLoop.Schedule(() => { Thread.CurrentThread.Name = "Uno Event Loop"; }, UI.Dispatching.NativeDispatcherPriority.Normal);

_eventLoop.Schedule(() =>
{
_isDispatcherThread = true;
_renderFrameRate = renderFrameRate;
}, UI.Dispatching.NativeDispatcherPriority.Normal);
CoreDispatcher.DispatchOverride = _eventLoop.Schedule;
CoreDispatcher.HasThreadAccessOverride = () => _isDispatcherThread;
}

internal static int RenderFrameRate => _renderFrameRate;
internal static int RenderFrameRate { get; private set; }

[LibraryImport("libc", StringMarshallingCustomType = typeof(AnsiStringMarshaller))]
private static partial void setlocale(int type, string s);
Expand Down
121 changes: 82 additions & 39 deletions src/Uno.UI.Runtime.Skia.X11/X11XamlRootHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,24 +73,28 @@ internal partial class X11XamlRootHost : IXamlRootHost
private readonly ApplicationView _applicationView;
private readonly X11WindowWrapper _wrapper;
private readonly Window _window;
private readonly CompositeDisposable _disposables = new();
private readonly XamlRoot _xamlRoot;

private int _synchronizedShutDownTopWindowIdleCounter;

private X11Window? _x11Window;
private X11Window? _x11TopWindow;
private IX11Renderer? _renderer;

private bool _renderDirty = true;
private readonly DispatcherTimer _renderTimer;
private static readonly Stopwatch _stopwatch = Stopwatch.StartNew();

private readonly DispatcherTimer _renderTimer = new DispatcherTimer();
private long _lastRenderTime;
private int _renderScheduled;

private readonly DispatcherTimer _configureTimer = new DispatcherTimer();
private long _lastConfigureTime;
private int _configureScheduled;

public X11Window RootX11Window => _x11Window!.Value;
public X11Window TopX11Window => _x11TopWindow!.Value;

public X11XamlRootHost(X11WindowWrapper wrapper, Window winUIWindow, XamlRoot xamlRoot, Action configureCallback, Action closingCallback, Action<bool> focusCallback, Action<bool> visibilityCallback)
{
_xamlRoot = xamlRoot;
_wrapper = wrapper;
_window = winUIWindow;

Expand All @@ -99,31 +103,28 @@ public X11XamlRootHost(X11WindowWrapper wrapper, Window winUIWindow, XamlRoot xa
_visibilityCallback = visibilityCallback;
_configureCallback = configureCallback;

_renderTimer = new DispatcherTimer();
_renderTimer.Interval = TimeSpan.FromSeconds(1.0 / X11ApplicationHost.RenderFrameRate); // we're on the UI thread
_renderTimer.Tick += (sender, o) =>
_closed = new TaskCompletionSource();
Closed = _closed.Task;

_renderTimer.Tick += (_, _) =>
{
if (Interlocked.Exchange(ref _needsConfigureCallback, 0) == 1)
{
_configureCallback();
}
_renderTimer.Stop();
_renderScheduled = 0;
_renderer?.Render();
};

if (_renderDirty)
{
_renderDirty = false;
_renderer?.Render();
}
_configureTimer.Tick += (_, _) =>
{
_configureTimer.Stop();
_configureScheduled = 0;
_configureCallback();
};
_renderTimer.Start();

_applicationView = ApplicationView.GetForWindowId(winUIWindow.AppWindow.Id);
_applicationView.PropertyChanged += OnApplicationViewPropertyChanged;
CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBarChanged += UpdateWindowPropertiesFromCoreApplication;
winUIWindow.AppWindow.TitleBar.ExtendsContentIntoTitleBarChanged += ExtendContentIntoTitleBar;

_closed = new TaskCompletionSource();
Closed = _closed.Task;

Initialize();

// Note: the timing of XamlRootMap.Register is very fragile. It needs to be early enough
Expand All @@ -132,6 +133,15 @@ public X11XamlRootHost(X11WindowWrapper wrapper, Window winUIWindow, XamlRoot xa
_windowToHost[winUIWindow] = this;
X11Manager.XamlRootMap.Register(xamlRoot, this);

UpdateWindowPropertiesFromPackage();
OnApplicationViewPropertyChanged(this, new PropertyChangedEventArgs(null));

// only start listening to events after we're done setting everything up
InitializeX11EventsThread();

var windowBackgroundDisposable = _window.RegisterBackgroundChangedEvent((_, _) => UpdateRendererBackground());
UpdateRendererBackground();

Closed.ContinueWith(_ =>
{
using (X11Helper.XLock(RootX11Window.Display))
Expand All @@ -141,16 +151,9 @@ public X11XamlRootHost(X11WindowWrapper wrapper, Window winUIWindow, XamlRoot xa
_applicationView.PropertyChanged -= OnApplicationViewPropertyChanged;
CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBarChanged -= UpdateWindowPropertiesFromCoreApplication;
winUIWindow.AppWindow.TitleBar.ExtendsContentIntoTitleBarChanged -= ExtendContentIntoTitleBar;
windowBackgroundDisposable.Dispose();
}
});

UpdateWindowPropertiesFromPackage();
OnApplicationViewPropertyChanged(this, new PropertyChangedEventArgs(null));

// only start listening to events after we're done setting everything up
InitializeX11EventsThread();

RegisterForBackgroundColor();
}

public static X11XamlRootHost? GetHostFromWindow(Window window)
Expand Down Expand Up @@ -444,7 +447,7 @@ private unsafe static X11Window CreateGLXWindow(IntPtr display, int screen, Size
}

IntPtr context = GlxInterface.glXCreateNewContext(display, bestFbc, GlxConsts.GLX_RGBA_TYPE, IntPtr.Zero, /* True */ 1);
var _1 = XLib.XSync(display, false);
_ = XLib.XSync(display, false);

XSetWindowAttributes attribs = default;
attribs.border_pixel = XLib.XBlackPixel(display, screen);
Expand Down Expand Up @@ -534,10 +537,57 @@ private bool IsOpenGLSupported(IntPtr display)
}
}

void IXamlRootHost.InvalidateRender() => _renderDirty = true;

UIElement? IXamlRootHost.RootElement => _window.RootElement;

// running XConfigureEvent and rendering callbacks on a timer is necessary to avoid freezing in certain situations
// where we get spammed with these events. Most notably, when resizing a window by dragging an edge, we'll get spammed
// with XConfigureEvents.
void IXamlRootHost.InvalidateRender()
{
if (Interlocked.Exchange(ref _renderScheduled, 1) == 0)
{
// Don't use ticks, which seem to mess things up for some reason
var now = _stopwatch.ElapsedMilliseconds;
var delta = now - Interlocked.Exchange(ref _lastRenderTime, now);
if (delta > TimeSpan.FromSeconds(1.0 / X11ApplicationHost.RenderFrameRate).TotalMilliseconds)
{
QueueAction(this, () =>
{
_renderScheduled = 0;
_renderer?.Render();
});
}
else
{
_renderTimer.Interval = TimeSpan.FromTicks(delta);
_renderTimer.Start();
}
}
}

private void RaiseConfigureCallback()
{
if (Interlocked.Exchange(ref _configureScheduled, 1) == 0)
{
// Don't use ticks, which seem to mess things up for some reason
var now = _stopwatch.ElapsedMilliseconds;
var delta = now - Interlocked.Exchange(ref _lastConfigureTime, now);
if (delta > TimeSpan.FromSeconds(1.0 / X11ApplicationHost.RenderFrameRate).TotalMilliseconds)
{
QueueAction(this, () =>
{
_configureScheduled = 0;
_configureCallback();
});
}
else
{
_configureTimer.Interval = TimeSpan.FromTicks(delta);
_configureTimer.Start();
}
}
}

public unsafe void AttachSubWindow(IntPtr window)
{
using var lockDisposable = X11Helper.XLock(RootX11Window.Display);
Expand Down Expand Up @@ -593,13 +643,6 @@ private void SynchronizedShutDown(X11Window x11Window)
}
}

private void RegisterForBackgroundColor()
{
UpdateRendererBackground();

_disposables.Add(_window.RegisterBackgroundChangedEvent((s, e) => UpdateRendererBackground()));
}

private void UpdateRendererBackground()
{
if (_window.Background is Microsoft.UI.Xaml.Media.SolidColorBrush brush)
Expand Down
8 changes: 3 additions & 5 deletions src/Uno.UI.Runtime.Skia.X11/X11XamlRootHost.x11events.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ internal partial class X11XamlRootHost
private readonly Action<bool> _visibilityCallback;
private readonly Action _configureCallback;

private int _needsConfigureCallback;

private X11PointerInputSource? _pointerSource;
private X11KeyboardInputSource? _keyboardSource;
private X11DragDropExtension? _dragDrop;
Expand Down Expand Up @@ -87,7 +85,7 @@ private unsafe void Run(X11Window x11Window)
{
var ret = X11Helper.poll(fds, 1, 1000); // timeout every second to see if the window is closed

if (_closed.Task.IsCompleted)
if (Closed.IsCompleted)
{
SynchronizedShutDown(x11Window);
return;
Expand Down Expand Up @@ -197,7 +195,7 @@ static IEnumerable<XEvent> GetEvents(IntPtr display)
}
break;
case XEventName.ConfigureNotify:
Interlocked.Exchange(ref _needsConfigureCallback, 1);
RaiseConfigureCallback();
break;
case XEventName.FocusIn:
QueueAction(this, () => _focusCallback(true));
Expand All @@ -209,7 +207,7 @@ static IEnumerable<XEvent> GetEvents(IntPtr display)
QueueAction(this, () => _visibilityCallback(@event.VisibilityEvent.state != /* VisibilityFullyObscured */ 2));
break;
case XEventName.Expose:
QueueAction(this, () => ((IXamlRootHost)this).InvalidateRender());
((IXamlRootHost)this).InvalidateRender();
break;
case XEventName.MotionNotify:
_pointerSource?.ProcessMotionNotifyEvent(@event.MotionEvent);
Expand Down
Loading

0 comments on commit 0265ec4

Please sign in to comment.