Browse Source

Implemented clipboard

Nikita Tsukanov 8 years ago
parent
commit
cc60c6e5dd

+ 1 - 0
src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj

@@ -44,6 +44,7 @@
     <Compile Include="..\Avalonia.Gtk\KeyTransform.cs">
       <Link>KeyTransform.cs</Link>
     </Compile>
+    <Compile Include="ClipboardImpl.cs" />
     <Compile Include="FramebufferManager.cs" />
     <Compile Include="GdkKey.cs" />
     <Compile Include="Gtk3Platform.cs" />

+ 53 - 0
src/Gtk/Avalonia.Gtk3/ClipboardImpl.cs

@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.Gtk3.Interop;
+using Avalonia.Input.Platform;
+
+namespace Avalonia.Gtk3
+{
+    class ClipboardImpl : IClipboard
+    {
+
+        IntPtr GetClipboard() => Native.GtkClipboardGetForDisplay(Native.GdkGetDefaultDisplay(), IntPtr.Zero);
+
+        static void OnText(IntPtr clipboard, IntPtr utf8string, IntPtr userdata)
+        {
+            var handle = GCHandle.FromIntPtr(userdata);
+
+            ((TaskCompletionSource<string>) handle.Target)
+                .TrySetResult(Utf8Buffer.StringFromPtr(utf8string));
+            handle.Free();
+        }
+
+        private static readonly Native.D.GtkClipboardTextReceivedFunc OnTextDelegate = OnText;
+
+        static ClipboardImpl()
+        {
+            GCHandle.Alloc(OnTextDelegate);
+        }
+
+        public Task<string> GetTextAsync()
+        {
+            var tcs = new TaskCompletionSource<string>();
+            Native.GtkClipboardRequestText(GetClipboard(), OnTextDelegate, GCHandle.ToIntPtr(GCHandle.Alloc(tcs)));
+            return tcs.Task;
+        }
+
+        public Task SetTextAsync(string text)
+        {
+            using (var buf = new Utf8Buffer(text))
+                Native.GtkClipboardSetText(GetClipboard(), buf, buf.ByteLen);
+            return Task.FromResult(0);
+        }
+
+        public Task ClearAsync()
+        {
+            Native.GtkClipboardRequestClear(GetClipboard());
+            return Task.FromResult(0);
+        }
+    }
+}

+ 1 - 1
src/Gtk/Avalonia.Gtk3/Gtk3Platform.cs

@@ -30,7 +30,7 @@ namespace Avalonia.Gtk3
             s_tlsMarker = true;
 
             AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatform>().ToConstant(Instance)
-                .Bind<IClipboard>().ToSingleton<ClipboardStub>()
+                .Bind<IClipboard>().ToSingleton<ClipboardImpl>()
                 .Bind<IStandardCursorFactory>().ToConstant(new CursorFactoryStub())
                 .Bind<IKeyboardDevice>().ToConstant(Keyboard)
                 .Bind<IMouseDevice>().ToConstant(Mouse)

+ 23 - 0
src/Gtk/Avalonia.Gtk3/Interop/Native.cs

@@ -57,6 +57,9 @@ namespace Avalonia.Gtk3.Interop
             [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
             public delegate int gdk_screen_get_width(IntPtr screen);
 
+            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
+            public delegate IntPtr gdk_display_get_default();
+
             [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
             public delegate int gdk_window_get_origin(IntPtr gdkWindow, out int x, out int y);
             [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
@@ -145,6 +148,18 @@ namespace Avalonia.Gtk3.Interop
             [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
             public delegate void gdk_window_begin_resize_drag(IntPtr window, WindowEdge edge, gint button, gint root_x, gint root_y, guint32 timestamp);
 
+            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
+            public delegate IntPtr gtk_clipboard_get_for_display(IntPtr display, IntPtr atom);
+
+            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
+            public delegate void gtk_clipboard_request_text(IntPtr clipboard, GtkClipboardTextReceivedFunc callback, IntPtr user_data);
+
+            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
+            public delegate void gtk_clipboard_set_text(IntPtr clipboard, Utf8Buffer text, int len);
+
+            [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gtk)]
+            public delegate void gtk_clipboard_clear(IntPtr clipboard);
+
             [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gobject)]
             public delegate ulong g_signal_connect_object(IntPtr instance, Utf8Buffer signal, IntPtr handler, IntPtr userData, int flags);
             [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gobject)]
@@ -165,6 +180,9 @@ namespace Avalonia.Gtk3.Interop
 
             [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
             public delegate bool timeout_callback(IntPtr data);
+
+            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+            public delegate void GtkClipboardTextReceivedFunc(IntPtr clipboard, IntPtr utf8string, IntPtr userdata);
         }
 
 
@@ -195,6 +213,10 @@ namespace Avalonia.Gtk3.Interop
         public static D.gdk_window_invalidate_rect GdkWindowInvalidateRect;
         public static D.gtk_widget_queue_draw_area GtkWidgetQueueDrawArea;
         public static D.gtk_widget_activate GtkWidgetActivate;
+        public static D.gtk_clipboard_get_for_display GtkClipboardGetForDisplay;
+        public static D.gtk_clipboard_request_text GtkClipboardRequestText;
+        public static D.gtk_clipboard_set_text GtkClipboardSetText;
+        public static D.gtk_clipboard_clear GtkClipboardRequestClear;
 
 
         public static D.gtk_im_multicontext_new GtkImMulticontextNew;
@@ -202,6 +224,7 @@ namespace Avalonia.Gtk3.Interop
         public static D.gtk_im_context_set_client_window GtkImContextSetClientWindow;
 
         public static D.gdk_screen_get_height GdkScreenGetHeight;
+        public static D.gdk_display_get_default GdkGetDefaultDisplay;
         public static D.gdk_screen_get_width GdkScreenGetWidth;
         public static D.gdk_screen_get_root_window GdkScreenGetRootWindow;
         public static D.gdk_window_get_origin GdkWindowGetOrigin;

+ 13 - 0
src/Gtk/Avalonia.Gtk3/Interop/Utf8Buffer.cs

@@ -16,6 +16,8 @@ namespace Avalonia.Gtk3.Interop
             handle = _gchandle.AddrOfPinnedObject();
         }
 
+        public int ByteLen => _data.Length;
+
         protected override bool ReleaseHandle()
         {
             if (handle != IntPtr.Zero)
@@ -28,5 +30,16 @@ namespace Avalonia.Gtk3.Interop
         }
 
         public override bool IsInvalid => handle == IntPtr.Zero;
+
+        public static unsafe string StringFromPtr(IntPtr s)
+        {
+            var pstr = (byte*)s;
+            int len;
+            for (len = 0; pstr[len] != 0; len++) ;
+            var bytes = new byte[len];
+            Marshal.Copy(s, bytes, 0, len);
+
+            return Encoding.UTF8.GetString(bytes, 0, len);
+        }
     }
 }

+ 0 - 9
src/Gtk/Avalonia.Gtk3/Stubs.cs

@@ -14,15 +14,6 @@ using Avalonia.Platform;
 
 namespace Avalonia.Gtk3
 {
-    class ClipboardStub : IClipboard
-    {
-        public Task<string> GetTextAsync() => Task.FromResult("");
-
-        public Task SetTextAsync(string text) => Task.FromResult(0);
-
-        public Task ClearAsync() => Task.FromResult(0);
-    }
-
     class CursorFactoryStub :  IStandardCursorFactory
     {
         public IPlatformHandle GetCursor(StandardCursorType cursorType) => new PlatformHandle(IntPtr.Zero, "STUB");

+ 1 - 7
src/Gtk/Avalonia.Gtk3/TopLevelImpl.cs

@@ -170,13 +170,7 @@ namespace Avalonia.Gtk3
 
         private unsafe bool OnCommit(IntPtr gtkwidget, IntPtr utf8string, IntPtr userdata)
         {
-            var pstr = (byte*)utf8string;
-            int len;
-            for (len = 0; pstr[len] != 0; len++) ;
-            var bytes = new byte[len];
-            Marshal.Copy(utf8string, bytes, 0, len);
-
-            Input(new RawTextInputEventArgs(Gtk3Platform.Keyboard, _lastKbdEvent, Encoding.UTF8.GetString(bytes, 0, len)));
+            Input(new RawTextInputEventArgs(Gtk3Platform.Keyboard, _lastKbdEvent, Utf8Buffer.StringFromPtr(utf8string)));
             return true;
         }