diff --git a/Source/Libs/GtkSharp/CellRenderer.GetSize.cs b/Source/Libs/GtkSharp/CellRenderer.GetSize.cs new file mode 100644 index 000000000..393f8aa4b --- /dev/null +++ b/Source/Libs/GtkSharp/CellRenderer.GetSize.cs @@ -0,0 +1,166 @@ +using GtkSharp; + +namespace Gtk +{ + + using System; + using System.Runtime.InteropServices; + + public partial class CellRenderer + { + static GetSizeNativeDelegate GetSize_cb_delegate; + + static GetSizeNativeDelegate GetSizeVMCallback { + get { + if (GetSize_cb_delegate == null) + GetSize_cb_delegate = new GetSizeNativeDelegate (GetSize_cb); + return GetSize_cb_delegate; + } + } + + static void OverrideGetSize (GLib.GType gtype) + { + OverrideGetSize (gtype, GetSizeVMCallback); + } + + /// + /// sets callback GetSize in GtkCellRendererClass-Struct + /// + /// + /// + static void OverrideGetSize (GLib.GType gtype, GetSizeNativeDelegate callback) + { + unsafe { + IntPtr* raw_ptr = (IntPtr*) (((long) gtype.GetClassPtr ()) + (long) class_abi.GetFieldOffset ("get_size")); + *raw_ptr = Marshal.GetFunctionPointerForDelegate ((Delegate) callback); + } + } + + // We have to implement this VM manually because x_offset, y_offset, width and height params may be NULL and therefore cannot be treated as "out int" + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void GetSizeNativeDelegate (IntPtr item, IntPtr widget, IntPtr cell_area_ptr, IntPtr x_offset, IntPtr y_offset, IntPtr width, IntPtr height); + + static void GetSize_cb (IntPtr item, IntPtr widget, IntPtr cell_area_ptr, IntPtr x_offset, IntPtr y_offset, IntPtr width, IntPtr height) + { + try { + CellRenderer obj = GLib.Object.GetObject (item, false) as CellRenderer; + Gtk.Widget widg = GLib.Object.GetObject (widget, false) as Gtk.Widget; + Gdk.Rectangle cell_area = Gdk.Rectangle.Zero; + if (cell_area_ptr != IntPtr.Zero) + cell_area = Gdk.Rectangle.New (cell_area_ptr); + int a, b, c, d; + + obj.OnGetSize (widg, ref cell_area, out a, out b, out c, out d); + if (x_offset != IntPtr.Zero) + Marshal.WriteInt32 (x_offset, a); + if (y_offset != IntPtr.Zero) + Marshal.WriteInt32 (y_offset, b); + if (width != IntPtr.Zero) + Marshal.WriteInt32 (width, c); + if (height != IntPtr.Zero) + Marshal.WriteInt32 (height, d); + } catch (Exception e) { + GLib.ExceptionManager.RaiseUnhandledException (e, false); + } + } + + [GLib.DefaultSignalHandler (Type = typeof(Gtk.CellRenderer), ConnectionMethod = nameof(OverrideGetSize))] + protected virtual void OnGetSize (Gtk.Widget widget, ref Gdk.Rectangle cell_area, out int x_offset, out int y_offset, out int width, out int height) + { + InternalOnGetSize (widget, ref cell_area, out x_offset, out y_offset, out width, out height); + } + + private void InternalOnGetSize (Gtk.Widget widget, ref Gdk.Rectangle cell_area, out int x_offset, out int y_offset, out int width, out int height) + { + IntPtr native_cell_area = GLib.Marshaller.StructureToPtrAlloc (cell_area); + gtksharp_cellrenderer_base_get_size (Handle, widget?.Handle ?? IntPtr.Zero, native_cell_area, out x_offset, out y_offset, out width, out height); + cell_area = Gdk.Rectangle.New (native_cell_area); + Marshal.FreeHGlobal (native_cell_area); + } + + static GetSizeNativeDelegate InternalGetSizeNativeDelegate (GLib.GType gtype) + { + GetSizeNativeDelegate unmanaged = null; + unsafe { + IntPtr* raw_ptr = (IntPtr*) (((long) gtype.GetClassPtr ()) + (long) class_abi.GetFieldOffset ("get_size")); + if (*raw_ptr == IntPtr.Zero) + return default; + + unmanaged = Marshal.GetDelegateForFunctionPointer (*raw_ptr); + } + + return unmanaged; + } + + static void gtksharp_cellrenderer_base_get_size (IntPtr cell, IntPtr widget, IntPtr cell_area, out int x_offset, out int y_offset, out int width, out int height) + { + /* + const gchar *__gtype_prefix = "__gtksharp_"; + #define HAS_PREFIX(a) (*((guint64 *)(a)) == *((guint64 *) __gtype_prefix)) + + static GObjectClass * + get_threshold_class (GObject *obj) + { + GType gtype = G_TYPE_FROM_INSTANCE (obj); + while (HAS_PREFIX (g_type_name (gtype))) + gtype = g_type_parent (gtype); + GObjectClass *klass = g_type_class_peek (gtype); + if (klass == NULL) klass = g_type_class_ref (gtype); + return klass; + } + + void gtksharp_cellrenderer_base_get_size (GtkCellRenderer *cell, GtkWidget *widget, GdkRectangle *cell_area, gint *x_offset, gint *y_offset, gint *width, gint *height) + { + GtkCellRendererClass *klass = (GtkCellRendererClass *) get_threshold_class (G_OBJECT (cell)); + if (klass->get_size) + (* klass->get_size) (cell, widget, cell_area, x_offset, y_offset, width, height); + } + */ + + x_offset = 0; + y_offset = 0; + width = 0; + height = 0; + + if (cell == IntPtr.Zero) { + return; + } + + var obj = TryGetObject (cell); + var parent = obj.NativeType; + while ((parent = parent.GetBaseType ()) != GLib.GType.None) { + if (parent.ToString ().StartsWith ("__gtksharp_")) { + continue; + } + + var GetSize = InternalGetSizeNativeDelegate (parent); + if (GetSize != default) { + var a = Marshal.AllocHGlobal (sizeof(int)); + var b = Marshal.AllocHGlobal (sizeof(int)); + var c = Marshal.AllocHGlobal (sizeof(int)); + var d = Marshal.AllocHGlobal (sizeof(int)); + try { + GetSize (cell, widget, cell_area, a, b, c, d); + if (a != IntPtr.Zero) + Marshal.WriteInt32 (a, x_offset); + if (b != IntPtr.Zero) + Marshal.WriteInt32 (b, y_offset); + if (c != IntPtr.Zero) + Marshal.WriteInt32 (c, width); + if (d != IntPtr.Zero) + Marshal.WriteInt32 (d, height); + } finally { + Marshal.FreeHGlobal (a); + Marshal.FreeHGlobal (b); + Marshal.FreeHGlobal (c); + Marshal.FreeHGlobal (d); + } + } + } + + return; + } + + } + +} \ No newline at end of file diff --git a/Source/Libs/GtkSharp/CellRenderer.cs b/Source/Libs/GtkSharp/CellRenderer.cs index 55543caa1..650e2309c 100644 --- a/Source/Libs/GtkSharp/CellRenderer.cs +++ b/Source/Libs/GtkSharp/CellRenderer.cs @@ -48,10 +48,6 @@ namespace Gtk { gtk_cell_renderer_render2 (Handle, context == null ? IntPtr.Zero : context.Handle, widget == null ? IntPtr.Zero : widget.Handle, ref background_area, ref cell_area, ref expose_area, (int) flags); } - // We have to implement this VM manually because x_offset, y_offset, width and height params may be NULL and therefore cannot be treated as "out int" - // TODO: Implement "nullable" attribute for value type parameters in GAPI - [UnmanagedFunctionPointer (CallingConvention.Cdecl)] - delegate void OnGetSizeDelegate (IntPtr item, IntPtr widget, IntPtr cell_area_ptr, IntPtr x_offset, IntPtr y_offset, IntPtr width, IntPtr height); } }