diff --git a/src/Uno.UI.Runtime.Skia.Gtk/GtkHost.cs b/src/Uno.UI.Runtime.Skia.Gtk/GtkHost.cs index c5da75b24ff3..e17c533fa54e 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/GtkHost.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/GtkHost.cs @@ -15,6 +15,7 @@ using Uno.UI.Runtime.Skia.GTK.Extensions.Helpers; using Uno.Extensions.System; using Uno.UI.Runtime.Skia.GTK.Extensions.System; +using Uno.UI.Runtime.Skia.GTK.UI.Core; namespace Uno.UI.Runtime.Skia { @@ -60,6 +61,13 @@ public void Run() _window.SetDefaultSize(1024, 800); _window.SetPosition(Gtk.WindowPosition.Center); + _window.Realized += (s, e) => + { + // Load the correct cursors before the window is shown + // but after the window has been initialized. + Cursors.Reload(); + }; + _window.DeleteEvent += delegate { Gtk.Application.Quit(); @@ -116,9 +124,9 @@ void Dispatch(System.Action d) _window.WindowStateEvent += OnWindowStateChanged; - var overlay = new Overlay(); + var overlay = new Overlay(); - _eventBox = new EventBox(); + _eventBox = new EventBox(); _area = new UnoDrawingArea(); _fix = new Fixed(); overlay.Add(_area); diff --git a/src/Uno.UI.Runtime.Skia.Gtk/UI/Core/CursorExtensions.cs b/src/Uno.UI.Runtime.Skia.Gtk/UI/Core/CursorExtensions.cs index 1877d2cc9dda..b517e11959fe 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/UI/Core/CursorExtensions.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/UI/Core/CursorExtensions.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Gdk; using Windows.UI.Core; +using Uno.UI.Runtime.Skia.GTK.UI.Core; namespace Uno.UI.Runtime.Skia.GTK.Extensions { @@ -12,38 +13,93 @@ internal static class CursorExtensions { public static CoreCursor ToCoreCursor(this Cursor cursor) { - CoreCursorType GetCoreCursorType(CursorType? type) => - type switch - { - CursorType.Arrow => CoreCursorType.Arrow, - CursorType.Cross => CoreCursorType.Cross, - CursorType.Hand1 => CoreCursorType.Hand, - CursorType.Hand2 => CoreCursorType.Hand, - CursorType.QuestionArrow => CoreCursorType.Help, - CursorType.Sizing => CoreCursorType.SizeAll, - CursorType.Watch => CoreCursorType.Wait, - _ => CoreCursorType.Arrow, - }; - - return new CoreCursor(GetCoreCursorType(cursor?.CursorType), 0); - } - - public static Cursor ToCursor(this CoreCursor coreCursor) - { - CursorType GetCursorType(CoreCursorType? coreCursorType) => - coreCursorType switch - { - CoreCursorType.Arrow => CursorType.Arrow, - CoreCursorType.Cross => CursorType.Cross, - CoreCursorType.Hand => CursorType.Hand1, - CoreCursorType.Help => CursorType.QuestionArrow, - CoreCursorType.SizeAll => CursorType.Sizing, - CoreCursorType.Wait => CursorType.Watch, - _ => CursorType.Arrow, - }; + CoreCursorType cursorType; + if (cursor == Cursors.Wait) + { + cursorType = CoreCursorType.Wait; + } + else if (cursor == Cursors.Pointer) + { + cursorType = CoreCursorType.Hand; + } + else if (cursor == Cursors.Crosshair) + { + cursorType = CoreCursorType.Cross; + } + else if (cursor == Cursors.Help) + { + cursorType = CoreCursorType.Help; + } + else if (cursor == Cursors.Text) + { + cursorType = CoreCursorType.IBeam; + } + else if (cursor == Cursors.NotAllowed) + { + cursorType = CoreCursorType.UniversalNo; + } + else if (cursor == Cursors.UpArrow) + { + cursorType = CoreCursorType.UpArrow; + } + else if (cursor == Cursors.NeswResize) + { + cursorType = CoreCursorType.SizeNortheastSouthwest; + } + else if (cursor == Cursors.NsResize) + { + cursorType = CoreCursorType.SizeNorthSouth; + } + else if (cursor == Cursors.NwseResize) + { + cursorType = CoreCursorType.SizeNorthwestSoutheast; + } + else if (cursor == Cursors.EwResize) + { + cursorType = CoreCursorType.SizeWestEast; + } + else + { + CoreCursorType GetCoreCursorType(CursorType? type) => + type switch + { + CursorType.Arrow => CoreCursorType.Arrow, + CursorType.Cross => CoreCursorType.Cross, + CursorType.Fleur => CoreCursorType.SizeAll, + CursorType.Hand1 => CoreCursorType.Hand, + CursorType.Hand2 => CoreCursorType.Hand, + CursorType.QuestionArrow => CoreCursorType.Help, + CursorType.SbUpArrow => CoreCursorType.UpArrow, + CursorType.SbHDoubleArrow => CoreCursorType.SizeWestEast, + CursorType.SbVDoubleArrow => CoreCursorType.SizeNorthSouth, + CursorType.Sizing => CoreCursorType.SizeAll, + CursorType.Watch => CoreCursorType.Wait, + CursorType.Xterm => CoreCursorType.IBeam, + _ => CoreCursorType.Arrow, + }; + cursorType = GetCoreCursorType(cursor?.CursorType); - return new Cursor(GetCursorType(coreCursor?.Type)); + } + return new CoreCursor(cursorType, 0); } - + + public static Cursor ToCursor(this CoreCursor coreCursor) => + coreCursor?.Type switch + { + CoreCursorType.Arrow => Cursors.Default, + CoreCursorType.Cross => Cursors.Crosshair, + CoreCursorType.Hand => Cursors.Pointer, + CoreCursorType.Help => Cursors.Help, + CoreCursorType.IBeam => Cursors.Text, + CoreCursorType.SizeAll => Cursors.AllScroll, + CoreCursorType.SizeNortheastSouthwest => Cursors.NeswResize, + CoreCursorType.SizeNorthSouth => Cursors.NsResize, + CoreCursorType.SizeNorthwestSoutheast => Cursors.NwseResize, + CoreCursorType.SizeWestEast => Cursors.EwResize, + CoreCursorType.UniversalNo => Cursors.NotAllowed, + CoreCursorType.UpArrow => Cursors.UpArrow, + CoreCursorType.Wait => Cursors.Wait, + _ => Cursors.Default + }; } } diff --git a/src/Uno.UI.Runtime.Skia.Gtk/UI/Core/Cursors.cs b/src/Uno.UI.Runtime.Skia.Gtk/UI/Core/Cursors.cs new file mode 100644 index 000000000000..71a66a169bb5 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Gtk/UI/Core/Cursors.cs @@ -0,0 +1,82 @@ +using Gdk; +using System; +using Uno.UI.Runtime.Skia; + +namespace Uno.UI.Runtime.Skia.GTK.UI.Core +{ + internal static class Cursors + { + private static Cursor _default; + public static Cursor Default => _default; + private static Cursor _crosshair; + public static Cursor Crosshair => _crosshair; + private static Cursor _pointer; + public static Cursor Pointer => _pointer; + private static Cursor _help; + public static Cursor Help => _help; + private static Cursor _text; + public static Cursor Text => _text; + private static Cursor _allScroll; + public static Cursor AllScroll => _allScroll; + private static Cursor _neswResize; + public static Cursor NeswResize => _neswResize; + private static Cursor _nsResize; + public static Cursor NsResize => _nsResize; + private static Cursor _nwseResize; + public static Cursor NwseResize => _nwseResize; + private static Cursor _ewResize; + public static Cursor EwResize => _ewResize; + private static Cursor _notAllowed; + public static Cursor NotAllowed => _notAllowed; + private static Cursor _upArrow; + public static Cursor UpArrow => _upArrow; + private static Cursor _wait; + public static Cursor Wait => _wait; + + public static void Reload() + { + // Name based on this: https://developer.gnome.org/gdk3/stable/gdk3-Cursors.html#gdk-cursor-new-from-name + // Fallback based on this list: https://developer.gnome.org/gdk3/stable/gdk3-Cursors.html#GdkCursorType + Set(ref _default, "default", CursorType.Arrow); + Set(ref _crosshair, "crosshair", CursorType.Cross); + Set(ref _pointer, "pointer", CursorType.Hand1); + Set(ref _help, "help", CursorType.QuestionArrow); + Set(ref _text, "text", CursorType.Xterm); + Set(ref _allScroll, "all-scroll", CursorType.Fleur); + Set(ref _neswResize, "nesw-resize"); + Set(ref _nsResize, "ns-resize", CursorType.SbVDoubleArrow); + Set(ref _nwseResize, "nwse-resize"); + Set(ref _ewResize, "ew-resize", CursorType.SbHDoubleArrow); + Set(ref _notAllowed, "not-allowed"); + Set(ref _upArrow, CursorType.SbUpArrow); + Set(ref _wait, "wait", CursorType.Watch); + } + + private static void Set(ref Cursor cursor, string name, CursorType fallback = CursorType.Arrow) + { + try + { + var display = GtkHost.Window.Window.Display; + if (display != null) + { + cursor = new Cursor(display, name); + // Library funtion returns null if theme does not contain cursor with name. + if (cursor.Handle != IntPtr.Zero) + { + return; + } + } + } + catch + { + // Fallback cursor should always work, ignore exception. + } + cursor = new Cursor(fallback); + } + + private static void Set(ref Cursor cursor, CursorType type) + { + cursor = new Cursor(type); + } + } +}