[NUI.WindowSystem] Introduce the new KVM service feature
authorJunseok Kim <juns.kim@samsung.com>
Thu, 27 Jul 2023 07:18:53 +0000 (16:18 +0900)
committerdongsug-song <35130733+dongsug-song@users.noreply.github.com>
Mon, 21 Aug 2023 08:44:12 +0000 (17:44 +0900)
Introduce the new KVM service feature and Add tests for the feature

Signed-off-by: Junseok Kim <juns.kim@samsung.com>
src/Tizen.NUI.WindowSystem/src/internal/Interop/Interop.KVMService.cs [new file with mode: 0644]
src/Tizen.NUI.WindowSystem/src/public/KVMService.cs [new file with mode: 0644]
test/NUIWindowKVMSample/NUIWindowKVMSample.cs [new file with mode: 0644]
test/NUIWindowKVMSample/NUIWindowKVMSample.csproj [new file with mode: 0644]
test/NUIWindowKVMSample/shared/res/NUIWindowKVMSample.png [new file with mode: 0644]
test/NUIWindowKVMSample/tizen-manifest.xml [new file with mode: 0644]
test/NUIWindowKVMSample/tizen_dotnet_project.yaml [new file with mode: 0644]

diff --git a/src/Tizen.NUI.WindowSystem/src/internal/Interop/Interop.KVMService.cs b/src/Tizen.NUI.WindowSystem/src/internal/Interop/Interop.KVMService.cs
new file mode 100644 (file)
index 0000000..52ee625
--- /dev/null
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tizen.NUI.WindowSystem.Shell
+{
+    internal static partial class Interop
+    {
+        internal static partial class KVMService
+        {
+            const string lib = "libtzsh_kvm_service.so.0";
+
+            [global::System.Runtime.InteropServices.DllImport(lib, EntryPoint = "tzsh_kvm_service_create")]
+            internal static extern IntPtr Create(IntPtr tzsh, IntPtr win);
+
+            [global::System.Runtime.InteropServices.DllImport(lib, EntryPoint = "tzsh_kvm_service_destroy")]
+            internal static extern int Destroy(IntPtr kvmService);
+
+            [global::System.Runtime.InteropServices.DllImport(lib, EntryPoint = "tzsh_kvm_service_perform_drop")]
+            internal static extern int PerformDrop(IntPtr kvmService);
+
+            [global::System.Runtime.InteropServices.DllImport(lib, EntryPoint = "tzsh_kvm_service_secondary_selection_set")]
+            internal static extern int SetSecondarySelection(IntPtr kvmService);
+
+            [global::System.Runtime.InteropServices.DllImport(lib, EntryPoint = "tzsh_kvm_service_secondary_selection_unset")]
+            internal static extern int UnsetSecondarySelection(IntPtr kvmService);
+
+            internal delegate void KVMDragStartEventCallback(IntPtr data, IntPtr kvmService);
+            [global::System.Runtime.InteropServices.DllImport(lib, EntryPoint = "tzsh_kvm_service_drag_start_cb_set")]
+            internal static extern int SetDragStartEventHandler(IntPtr kvmService, KVMDragStartEventCallback func, IntPtr data);
+
+            internal delegate void KVMDragEndEventCallback(IntPtr data, IntPtr kvmService);
+            [global::System.Runtime.InteropServices.DllImport(lib, EntryPoint = "tzsh_kvm_service_drag_end_cb_set")]
+            internal static extern int SetDragEndEventHandler(IntPtr kvmService, KVMDragEndEventCallback func, IntPtr data);
+        }
+    }
+}
diff --git a/src/Tizen.NUI.WindowSystem/src/public/KVMService.cs b/src/Tizen.NUI.WindowSystem/src/public/KVMService.cs
new file mode 100644 (file)
index 0000000..febc473
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.ComponentModel;
+
+namespace Tizen.NUI.WindowSystem.Shell
+{
+    /// <summary>
+    /// Class for the Tizen KVM service.
+    /// </summary>
+    /// This class is need to be hidden as inhouse API.
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class KVMService : IDisposable
+    {
+        private TizenShell _tzsh;
+        private IntPtr _kvmService;
+        private int _tzshWin;
+        private bool disposed = false;
+        private bool isDisposeQueued = false;
+
+        private Interop.KVMService.KVMDragStartEventCallback _onDragStarted;
+        private Interop.KVMService.KVMDragEndEventCallback _onDragEnded;
+
+        private event EventHandler _dragStarted;
+        private event EventHandler _dragEnded;
+
+        /// <summary>
+        /// Creates a new KVM Service handle.
+        /// </summary>
+        /// <param name="tzShell">The TizenShell instance.</param>
+        /// <param name="win">The window to provide service of the quickpanel.</param>
+        /// <exception cref="ArgumentException">Thrown when failed of invalid argument.</exception>
+        /// <exception cref="ArgumentNullException">Thrown when a argument is null.</exception>
+        public KVMService(TizenShell tzShell, Window win)
+        {
+            if (tzShell == null)
+            {
+                throw new ArgumentNullException(nameof(tzShell));
+            }
+            if (tzShell.GetNativeHandle() == IntPtr.Zero)
+            {
+                throw new ArgumentException("tzShell is not initialized.");
+            }
+            if (win == null)
+            {
+                throw new ArgumentNullException(nameof(win));
+            }
+
+            _tzsh = tzShell;
+            _tzshWin = win.GetNativeId();
+            _kvmService = Interop.KVMService.Create(_tzsh.GetNativeHandle(), (IntPtr)_tzshWin);
+            if (_kvmService == IntPtr.Zero)
+            {
+                int err = Tizen.Internals.Errors.ErrorFacts.GetLastResult();
+                _tzsh.ErrorCodeThrow(err);
+            }
+        }
+
+        /// <summary>
+        /// Destructor.
+        /// </summary>
+        ~KVMService()
+        {
+            if (!isDisposeQueued)
+            {
+                isDisposeQueued = true;
+                DisposeQueue.Instance.Add(this);
+            }
+        }
+
+        /// <summary>
+        /// Dispose.
+        /// </summary>
+        public void Dispose()
+        {
+            if (isDisposeQueued)
+            {
+                Dispose(DisposeTypes.Implicit);
+            }
+            else
+            {
+                Dispose(DisposeTypes.Explicit);
+                GC.SuppressFinalize(this);
+            }
+        }
+
+        /// <inheritdoc/>
+        protected virtual void Dispose(DisposeTypes type)
+        {
+            if (!disposed)
+            {
+                if (_kvmService != IntPtr.Zero)
+                {
+                    int res = Interop.KVMService.Destroy(_kvmService);
+                    _kvmService = IntPtr.Zero;
+                }
+                disposed = true;
+            }
+        }
+
+        /// <summary>
+        /// Emits the event when the drag started from any window.
+        /// </summary>
+        /// <exception cref="ArgumentException">Thrown when failed of invalid argument.</exception>
+        public event EventHandler DragStarted
+        {
+            add
+            {
+                if (_dragStarted == null)
+                {
+                    _onDragStarted = OnDragStarted;
+                    int res = Interop.KVMService.SetDragStartEventHandler(_kvmService, _onDragStarted, IntPtr.Zero);
+                    _tzsh.ErrorCodeThrow(res);
+                }
+                _dragStarted += value;
+            }
+            remove
+            {
+                _dragStarted -= value;
+                if (_dragStarted == null)
+                {
+                    int res = Interop.KVMService.SetDragStartEventHandler(_kvmService, null, IntPtr.Zero);
+                    _tzsh.ErrorCodeThrow(res);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Emits the event when the drag ended on any window except KVM window.
+        /// </summary>
+        /// <exception cref="ArgumentException">Thrown when failed of invalid argument.</exception>
+        public event EventHandler DragEnded
+        {
+            add
+            {
+                if (_dragEnded == null)
+                {
+                    _onDragEnded = OnDragEnded;
+                    int res = Interop.KVMService.SetDragEndEventHandler(_kvmService, _onDragEnded, IntPtr.Zero);
+                    _tzsh.ErrorCodeThrow(res);
+                }
+                _dragEnded += value;
+            }
+            remove
+            {
+                _dragEnded -= value;
+                if (_dragEnded == null)
+                {
+                    int res = Interop.KVMService.SetDragEndEventHandler(_kvmService, null, IntPtr.Zero);
+                    _tzsh.ErrorCodeThrow(res);
+                }
+            }
+        }
+
+        private void OnDragStarted(IntPtr data, IntPtr softkeyService)
+        {
+            _dragStarted?.Invoke(this, EventArgs.Empty);
+        }
+
+        private void OnDragEnded(IntPtr data, IntPtr softkeyService)
+        {
+            _dragEnded?.Invoke(this, EventArgs.Empty);
+        }
+
+        /// <summary>
+        /// Requests to perform drop to KVM window.
+        /// </summary>
+        /// <exception cref="ArgumentException">Thrown when failed of invalid argument.</exception>
+        public void PerformDrop()
+        {
+            int res = Interop.KVMService.PerformDrop(_kvmService);
+            _tzsh.ErrorCodeThrow(res);
+        }
+
+        /// <summary>
+        /// Requests to set KVM window as secondary selection window.
+        /// </summary>
+        /// <exception cref="ArgumentException">Thrown when failed of invalid argument.</exception>
+        public void SetSecondarySelction()
+        {
+            int res = Interop.KVMService.SetSecondarySelection(_kvmService);
+            _tzsh.ErrorCodeThrow(res);
+        }
+
+        /// <summary>
+        /// Requests to unset secondary selection window of KVM window.
+        /// </summary>
+        /// <exception cref="ArgumentException">Thrown when failed of invalid argument.</exception>
+        public void UnsetSecondarySelction()
+        {
+            int res = Interop.KVMService.UnsetSecondarySelection(_kvmService);
+            _tzsh.ErrorCodeThrow(res);
+        }
+    }
+}
diff --git a/test/NUIWindowKVMSample/NUIWindowKVMSample.cs b/test/NUIWindowKVMSample/NUIWindowKVMSample.cs
new file mode 100644 (file)
index 0000000..3fcc072
--- /dev/null
@@ -0,0 +1,151 @@
+using System;
+using Tizen;
+using Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.WindowSystem;
+using System.Collections.Generic;
+
+namespace NUIWindowKVMSample
+{
+    class Program : NUIApplication
+    {
+        protected override void OnCreate()
+        {
+            base.OnCreate();
+            Initialize();
+        }
+
+        void Initialize()
+        {
+            Window win = Window.Instance;
+            dnd = DragAndDrop.Instance;
+
+            win.WindowSize = new Size2D(500, 500);
+            win.KeyEvent += OnKeyEvent;
+            win.BackgroundColor = Color.White;
+
+            View windowView = new View();
+            windowView.Size2D = new Size2D(500, 500);
+            windowView.BackgroundColor = Color.White;
+            windowView.TouchEvent += OnTouchEvent;
+            win.Add(windowView);
+
+            TextLabel text = new TextLabel("Start drag here");
+            text.HorizontalAlignment = HorizontalAlignment.Center;
+            text.VerticalAlignment = VerticalAlignment.Center;
+            text.TextColor = Color.Black;
+            text.PointSize = 12.0f;
+            text.HeightResizePolicy = ResizePolicyType.FillToParent;
+            text.WidthResizePolicy = ResizePolicyType.FillToParent;
+            windowView.Add(text);
+
+            KVMServiceWindow kvmServiceWindow = new KVMServiceWindow(new Rectangle(2500, 0, 60, 1440));
+            kvmServiceWindow.Show();
+        }
+
+        private void OnKeyEvent(object sender, Window.KeyEventArgs e)
+        {
+            if (e.Key.State == Key.StateType.Down && (e.Key.KeyPressedName == "XF86Back" || e.Key.KeyPressedName == "Escape"))
+            {
+                Exit();
+            }
+        }
+
+        private bool OnTouchEvent(object sender, View.TouchEventArgs e)
+        {
+            if (e.Touch.GetState(0) == PointStateType.Down)
+            {
+                View shadowView = new ImageView(Tizen.Applications.Application.Current.DirectoryInfo.SharedResource + "NUIWindowKVMSample.png");
+                shadowView.Size = new Size(100, 100);
+
+                DragData dragData;
+                dragData.MimeType = "text/plain";
+                dragData.Data = "Hello World";
+                dnd.StartDragAndDrop((View)sender, shadowView, dragData, OnSourceEventHandler);
+
+                return true;
+            }
+
+            return false;
+        }
+
+        private void OnSourceEventHandler(DragSourceEventType e)
+        {
+            if (e == DragSourceEventType.Start)
+            {
+                Log.Debug("KVMSample", "Source App SourceEvnetType: Start");
+            }
+            else if (e == DragSourceEventType.Cancel)
+            {
+                Log.Debug("KVMSample", "Source App SourceEvnetType: Cancel");
+            }
+            else if (e == DragSourceEventType.Accept)
+            {
+                Log.Debug("KVMSample", "Source App SourceEvnetType: Accept");
+            }
+            else if (e == DragSourceEventType.Finish)
+            {
+                Log.Debug("KVMSample", "Source App SourceEvnetType: Finish");
+            }
+        }
+
+        static void Main(string[] args)
+        {
+            var app = new Program();
+            app.Run(args);
+        }
+
+        private DragAndDrop dnd;
+    }
+
+    class KVMServiceWindow : Window
+    {
+        public KVMServiceWindow(Rectangle winGeometry) :
+        base("KVM service Window", new Rectangle(winGeometry.X, winGeometry.Y, winGeometry.Width, winGeometry.Height))
+        {
+            dnd = DragAndDrop.Instance;
+            this.WindowSize = new Size2D(winGeometry.Width, winGeometry.Height);
+            this.BackgroundColor = Color.Yellow;
+
+            View windowView = new View();
+            windowView.Size2D = new Size2D(winGeometry.Width, winGeometry.Height);
+            windowView.BackgroundColor = Color.Yellow;
+            this.Add(windowView);
+
+            dnd.AddListener(windowView, OnDnDEvent);
+
+            tzShell = new Tizen.NUI.WindowSystem.Shell.TizenShell();
+            kvmService = new Tizen.NUI.WindowSystem.Shell.KVMService(tzShell, this);
+            kvmService.SetSecondarySelction();
+            kvmService.DragStarted += OnDragStarted;
+            kvmService.DragEnded += OnDragEnded;
+        }
+
+        private void OnDnDEvent(object sender, DragEvent e)
+        {
+            if (e.DragType == DragType.Enter)
+            {
+                Log.Debug("KVMSample", "Target(KVM) App DRagEvnetType: Enter");
+                kvmService.PerformDrop();
+            }
+            if (e.DragType == DragType.Drop)
+            {
+                Log.Debug("KVMSample", "Target(KVM) App DRagEvnetType: Drop, Data: " + e.Data);
+            }
+        }
+
+        private void OnDragStarted(object sender, EventArgs e)
+        {
+            Log.Debug("KVMSample", "Tizen KVM: Drag started");
+        }
+
+        private void OnDragEnded(object sender, EventArgs e)
+        {
+            Log.Debug("KVMSample", "Tizen KVM: Drag ended");
+        }
+
+        private DragAndDrop dnd;
+        private Tizen.NUI.WindowSystem.Shell.TizenShell tzShell;
+        private Tizen.NUI.WindowSystem.Shell.KVMService kvmService;
+    }
+}
diff --git a/test/NUIWindowKVMSample/NUIWindowKVMSample.csproj b/test/NUIWindowKVMSample/NUIWindowKVMSample.csproj
new file mode 100644 (file)
index 0000000..b0bb521
--- /dev/null
@@ -0,0 +1,27 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+      <OutputType>Exe</OutputType>
+      <TargetFramework>net6.0</TargetFramework>
+  </PropertyGroup>
+
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+      <DebugType>portable</DebugType>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+      <DebugType>None</DebugType>
+  </PropertyGroup>
+
+  <ItemGroup>
+      <PackageReference Include="Tizen.NET.Sdk" Version="1.0.9" />
+      <ProjectReference Include="../../src/Tizen/Tizen.csproj" />
+      <ProjectReference Include="../../src/Tizen.NUI.Components/Tizen.NUI.Components.csproj" />
+      <ProjectReference Include="../../src/Tizen.NUI/Tizen.NUI.csproj" />
+      <ProjectReference Include="../../src/Tizen.NUI.WindowSystem/Tizen.NUI.WindowSystem.csproj" />
+  </ItemGroup>
+
+  <PropertyGroup>
+      <NeedInjection>True</NeedInjection>
+  </PropertyGroup>
+
+</Project>
diff --git a/test/NUIWindowKVMSample/shared/res/NUIWindowKVMSample.png b/test/NUIWindowKVMSample/shared/res/NUIWindowKVMSample.png
new file mode 100644 (file)
index 0000000..9f3cb98
Binary files /dev/null and b/test/NUIWindowKVMSample/shared/res/NUIWindowKVMSample.png differ
diff --git a/test/NUIWindowKVMSample/tizen-manifest.xml b/test/NUIWindowKVMSample/tizen-manifest.xml
new file mode 100644 (file)
index 0000000..db99f83
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns="http://tizen.org/ns/packages" api-version="7.5" package="org.tizen.example.NUIWindowKVMSample" version="1.0.0">
+  <profile name="common" />
+  <ui-application appid="org.tizen.example.NUIWindowKVMSample"
+                                       exec="NUIWindowKVMSample.dll"
+                                       type="dotnet-nui"
+                                       multiple="false"
+                                       taskmanage="true"
+                                       nodisplay="false"
+                                       launch_mode="single"
+                    api-version="10">
+    <label>NUIWindowKVMSample</label>
+    <icon>NUIWindowKVMSample.png</icon>
+    <metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
+  </ui-application>
+</manifest>
diff --git a/test/NUIWindowKVMSample/tizen_dotnet_project.yaml b/test/NUIWindowKVMSample/tizen_dotnet_project.yaml
new file mode 100644 (file)
index 0000000..7576c55
--- /dev/null
@@ -0,0 +1,9 @@
+# csproj file path
+csproj_file: NUIWindowKVMSample.csproj
+
+# files monitored for dirty/modified status
+files:
+  - NUIWindowKVMSample.csproj
+  - NUIWindowKVMSample.cs
+  - tizen-manifest.xml
+  - shared/res/NUIWindowKVMSample.png
\ No newline at end of file