Skip to content

Commit

Permalink
Merge pull request #7234 from unoplatform/dev/dr/skiaPtDblClick
Browse files Browse the repository at this point in the history
Misc fixes for pointers
  • Loading branch information
dr1rrb committed Sep 30, 2021
2 parents 45162f3 + 3578c7c commit 1f8d45f
Show file tree
Hide file tree
Showing 23 changed files with 379 additions and 182 deletions.
5 changes: 5 additions & 0 deletions build/PackageDiffIgnore.xml
Expand Up @@ -3964,6 +3964,11 @@
fullName="Windows.UI.Xaml.Media.Animation.KeyTime Windows.UI.Xaml.Media.Animation.ObjectKeyFrame.get_KeyTime()"
reason="False positive, still present, but accessible also through an internal interface" />
</Methods>
<Types>
<Member
fullName="Windows.UI.Core.ICoreWindowExtension"
reason="Internal interface" />
</Types>
</IgnoreSet>
<!--
Supported nodes (please keep at the bottom of this file):
Expand Down
102 changes: 54 additions & 48 deletions src/Uno.UI.RemoteControl/RemoteControlClient.cs
Expand Up @@ -23,7 +23,7 @@ public class RemoteControlClient : IRemoteControlClient

public Type AppType { get; }

private readonly (string endpoint, int port)[] _serverAdresses;
private readonly (string endpoint, int port)[] _serverAddresses;
private WebSocket _webSocket;
private Dictionary<string, IRemoteControlProcessor> _processors = new Dictionary<string, IRemoteControlProcessor>();

Expand All @@ -33,14 +33,33 @@ private RemoteControlClient(Type appType)

if(appType.Assembly.GetCustomAttributes(typeof(ServerEndpointAttribute), false) is ServerEndpointAttribute[] endpoints)
{
_serverAdresses = endpoints
.Select(e => (endpoint: e.Endpoint, port: e.Port))
.ToArray();
IEnumerable<(string endpoint, int port)> GetAddresses()
{
foreach (var endpoint in endpoints)
{
if (endpoint.Port == 0)
{
this.Log().LogError($"Failed to get remote control server port from the IDE for endpoint {endpoint.Endpoint}.");
}
else
{
yield return (endpoint.Endpoint, endpoint.Port);
}
}
}

_serverAddresses = GetAddresses().ToArray();
}

StartConnection();
if ((_serverAddresses?.Length ?? 0) == 0)
{
this.Log().LogError("Failed to get any remote control server endpoint from the IDE.");

return;
}

RegisterProcessor(new HotReload.ClientHotReloadProcessor(this));
StartConnection();
}

private void RegisterProcessor(IRemoteControlProcessor processor)
Expand All @@ -52,7 +71,7 @@ private async Task StartConnection()
{
try
{
async Task<WebSocket> Connect(string endpoint, int port, CancellationToken ct)
async Task<(string endPoint, int port, WebSocket socket)> Connect(string endpoint, int port, CancellationToken ct)
{
#if __WASM__
var s = new Uno.Wasm.WebSockets.WasmWebSocket();
Expand Down Expand Up @@ -81,73 +100,60 @@ async Task<WebSocket> Connect(string endpoint, int port, CancellationToken ct)
await s.ConnectAsync(new Uri($"ws://{endpoint}:{port}/rc"), ct);
}

return s;
return (endpoint, port, s);
}

var connections = _serverAdresses.Select(s =>
{
var cts = new CancellationTokenSource();
if (s.port == 0)
{
return (
task: Task.FromException<WebSocket>(new InvalidOperationException($"Failed to get remote control server port from the IDE")),
cts: cts
);
}
else
var connections = _serverAddresses
.Where(adr => adr.port != 0)
.Select(s =>
{
if (this.Log().IsEnabled(LogLevel.Debug))
{
this.Log().LogDebug($"Connecting to {s}...");
}
var cts = new CancellationTokenSource();
var task = Connect(s.endpoint, s.port, cts.Token);
return (task, cts);
}
}).ToArray();
})
.ToArray();

var allCts = new TaskCompletionSource<int>();
var timeout = Task.Delay(30000);
var completed = await Task.WhenAny(connections.Select(c => c.task).Concat(timeout));

for (int i = 0; i < connections.Length; i++)
foreach (var connection in connections)
{
var connectionIndex = i;
connections[i]
.task
.ContinueWith(a => {
if(a.Status == TaskStatus.RanToCompletion)
{
allCts.SetResult(connectionIndex);
}
});
}

Task.Delay(30000)
.ContinueWith(a => allCts.SetException(new TimeoutException()));
if (connection.task == completed)
{
continue;
}

var index = await allCts.Task;
connection.cts.Cancel();
if (connection.task.Status == TaskStatus.RanToCompletion)
{
connection.task.Result.socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
}
}

for (int i = 0; i < connections.Length; i++)
if (completed == timeout)
{
if (i != index)
if (this.Log().IsEnabled(LogLevel.Error))
{
var connection = connections[i];
connection.cts.Cancel();

if (connection.task.Status == TaskStatus.RanToCompletion)
{
connections[i].task.Result.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
}
this.Log().LogError("Failed to connect to the server (timeout).");
}

return;
}

_webSocket = connections[index].task.Result;
var connected = ((Task<(string endPoint, int port, WebSocket socket)>)completed).Result;

if (this.Log().IsEnabled(LogLevel.Debug))
{
this.Log().LogDebug($"Connected to {_serverAdresses[index]}");
this.Log().LogDebug($"Connected to {connected.endPoint}:{connected.port}");
}

_webSocket = connected.socket;
await ProcessMessages();
}
catch (Exception ex)
Expand Down
69 changes: 60 additions & 9 deletions src/Uno.UI.Runtime.Skia.Gtk/GtkCoreWindowExtension.cs
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Gdk;
using Gtk;
Expand All @@ -9,15 +10,21 @@
using Windows.System;
using Windows.UI.Core;
using Windows.UI.Input;
using Microsoft.Extensions.Logging;
using static Windows.UI.Input.PointerUpdateKind;
using Device = Gtk.Device;
using Exception = System.Exception;

namespace Uno.UI.Runtime.Skia
{
internal partial class GtkCoreWindowExtension : ICoreWindowExtension
{
private readonly CoreWindow _owner;
private ICoreWindowEvents _ownerEvents;
private readonly ICoreWindowEvents _ownerEvents;

private const int _maxKnownDevices = 63;
private const int _knownDeviceScavengeCount = 16;
private readonly Dictionary<PointerIdentifier, (Gdk.Device dev, uint ts)> _knownDevices = new Dictionary<PointerIdentifier, (Gdk.Device dev, uint ts)>(_maxKnownDevices + 1);

internal const Gdk.EventMask RequestedEvents =
Gdk.EventMask.EnterNotifyMask
Expand All @@ -38,13 +45,6 @@ public CoreCursor PointerCursor
set => GtkHost.Window.Window.Cursor = value.ToCursor();
}

/// <inheritdoc />
public void ReleasePointerCapture()
=> this.Log().Warn("Pointer capture release is not supported on GTK");

/// <inheritdoc />
public void SetPointerCapture()
=> this.Log().Warn("Pointer capture is not supported on GTK");

public GtkCoreWindowExtension(object owner)
{
Expand Down Expand Up @@ -72,6 +72,32 @@ public GtkCoreWindowExtension(object owner)

partial void InitializeKeyboard();

/// <inheritdoc />
public void SetPointerCapture(PointerIdentifier pointer)
{
if (_knownDevices.TryGetValue(pointer, out var entry))
{
Gtk.Device.GrabAdd(GtkHost.Window, entry.dev, block_others: false);
}
else if (this.Log().IsEnabled(LogLevel.Error))
{
this.Log().Error($"Unknown device id {pointer}, unable to natively capture it.");
}
}

/// <inheritdoc />
public void ReleasePointerCapture(PointerIdentifier pointer)
{
if (_knownDevices.TryGetValue(pointer, out var entry))
{
Gtk.Device.GrabRemove(GtkHost.Window, entry.dev);
}
else if (this.Log().IsEnabled(LogLevel.Error))
{
this.Log().Error($"Unknown device id {pointer}, unable to natively capture it.");
}
}

private void OnWindowEnterEvent(object o, EnterNotifyEventArgs args)
{
try
Expand Down Expand Up @@ -233,7 +259,28 @@ private void OnWindowProximityInEvent(object o, ProximityInEventArgs args)
}
}

private static PointerEventArgs AsPointerArgs(Event evt)
private void UseDevice(PointerPoint pointer, Gdk.Device device)
{
_knownDevices[pointer.Pointer] = (device, pointer.FrameId);

if (_knownDevices.Count > _maxKnownDevices)
{
// If we have too much devices in the cache, we significantly trim it to not have to do that every times.

var oldest = _knownDevices
.OrderBy(kvp => kvp.Value.ts)
.Take(_knownDeviceScavengeCount)
.Select(kvp => kvp.Key)
.ToArray();

foreach (var dev in oldest)
{
_knownDevices.Remove(dev);
}
}
}

private PointerEventArgs AsPointerArgs(Event evt)
{
var dev = EventHelper.GetSourceDevice(evt); // We use GetSourceDevice (and not GetDevice) in order to get the TouchScreen device
var pointerDevice = ToPointerDevice(dev);
Expand Down Expand Up @@ -351,6 +398,10 @@ private static PointerEventArgs AsPointerArgs(Event evt)
properties: properties
);

// This method is not pure as it should be for a 'AsXXXX' method due to the line below,
// but doing so the 'dev' is contains only here.
UseDevice(pointerPoint, dev);

return new PointerEventArgs(pointerPoint, modifiers);
}

Expand Down
Expand Up @@ -125,9 +125,9 @@ private void RaisePointerEvent(Action<PointerEventArgs> raisePointerEvent, Point

public CoreCursor PointerCursor { get => new CoreCursor(CoreCursorType.Arrow, 0); set { } }

public void ReleasePointerCapture() { }
public void SetPointerCapture(PointerIdentifier pointer) { }

public void SetPointerCapture() { }
public void ReleasePointerCapture(PointerIdentifier pointer) { }

public void Dispose()
{
Expand Down
9 changes: 4 additions & 5 deletions src/Uno.UI.Runtime.Skia.Tizen/TizenCoreWindowExtension.cs
Expand Up @@ -62,13 +62,12 @@ public TizenCoreWindowExtension(object owner, UnoCanvas canvas)
}

/// <inheritdoc />
public void ReleasePointerCapture()
=> this.Log().Warn("Pointer capture release is not supported on Tizen");

/// <inheritdoc />
public void SetPointerCapture()
public void SetPointerCapture(PointerIdentifier pointer)
=> this.Log().Warn("Pointer capture is not supported on Tizen");

/// <inheritdoc />
public void ReleasePointerCapture(PointerIdentifier pointer)
=> this.Log().Warn("Pointer capture release is not supported on Tizen");

private void SetupTapGesture()
{
Expand Down
8 changes: 4 additions & 4 deletions src/Uno.UI.Runtime.Skia.Wpf/WpfCoreWindowExtension.cs
Expand Up @@ -84,12 +84,12 @@ void HookNative(object sender, RoutedEventArgs e)
}
}

public void ReleasePointerCapture()
=> WpfHost.Current.ReleaseMouseCapture();

public void SetPointerCapture()
public void SetPointerCapture(PointerIdentifier pointer)
=> WpfHost.Current.CaptureMouse();

public void ReleasePointerCapture(PointerIdentifier pointer)
=> WpfHost.Current.ReleaseMouseCapture();

private static uint GetNextFrameId()
=> (uint)Interlocked.Increment(ref _currentFrameId);

Expand Down

0 comments on commit 1f8d45f

Please sign in to comment.