gir.core icon indicating copy to clipboard operation
gir.core copied to clipboard

can't get text iterators from a TextBuffer

Open medovina opened this issue 10 months ago • 3 comments

Gir.Core doesn't seem to expose any methods that would return a Gtk.TextIter from a Gtk.TextBuffer. This seriously limits the set of operations that a program may perform with a TextBuffer. For example:

medovina avatar Feb 15 '25 14:02 medovina

If you open issues which directly reference some c api please insert links to the documentation. This makes life for me easier.

badcel avatar Feb 15 '25 17:02 badcel

OK, no problem. I just edited my posting above and added links to it.

medovina avatar Feb 16 '25 07:02 medovina

Hey! I'm trying to implement these (gtk_text_buffer_get_start_iter() and gtk_text_buffer_get_end_iter()) methods so I added 2 files to Internal and Public folders inside Gtk-4 Lib with native function calls. While it seems to work inside these methods (checked with debugger TextIter objects are created) the test app crushes right after return call.

Could you help me and point me where to dig?

Internal/TextBuffer.Methods.cs

public partial class TextBuffer
{
    [DllImport(ImportResolver.Library, EntryPoint = "gtk_text_buffer_get_start_iter")]
    public static extern void GetStartIter(IntPtr buffer, out IntPtr iter);

    [DllImport(ImportResolver.Library, EntryPoint = "gtk_text_buffer_get_end_iter")]
    public static extern void GetEndIter(IntPtr buffer, out IntPtr iter);
}
Public/TextBuffer.Methods.cs


public partial class TextBuffer
{
    public Gtk.TextIter GetStartIter()
    {
        Internal.TextBuffer.GetStartIter(Handle.DangerousGetHandle(), out var iter);
        var owned = TextIterOwnedHandle.FromUnowned(iter);
        return new TextIter(owned);
    }

    public Gtk.TextIter GetEndIter()
    {
        Internal.TextBuffer.GetEndIter(Handle.DangerousGetHandle(), out var iter);
        var owned = TextIterOwnedHandle.FromUnowned(iter);
        return new TextIter(owned);
    }
}
Program.cs

using Gtk;

GtkSource.Module.Initialize();

var application = Gtk.Application.New("org.gir.core", Gio.ApplicationFlags.FlagsNone);

application.OnActivate += (sender, args) =>
{
    var window = Gtk.ApplicationWindow.New((Gtk.Application) sender);
    window.Title = "GtkSource5 Demo";
    window.SetDefaultSize(300, 300);
    
    var boldTag = TextTag.New("bold");
    var tagTable = TextTagTable.New();
    tagTable.Add(boldTag);
    var buf = GtkSource.Buffer.New(tagTable);
    var view = GtkSource.View.NewWithBuffer(buf);
    
    buf.SetText("Lorem Ipsum\nDolor sit amet\nConsectetur adipiscing elit", -1);
    TextIter startIter = buf.GetStartIter();
    TextIter endIter = buf.GetEndIter();

    buf.ApplyTag(boldTag, startIter, endIter);

    view.Monospace = true;
    view.ShowLineNumbers = true;

    var settings = Gtk.Settings.GetDefault();

    if (settings?.GtkApplicationPreferDarkTheme == true ||
        settings?.GtkThemeName?.ToLower()?.Contains("dark") == true)
        buf.SetStyleScheme(GtkSource.StyleSchemeManager.GetDefault().GetScheme("Adwaita-dark"));

    window.Child = view;
    window.Show();
};

return application.RunWithSynchronizationContext(null);

amka avatar Jun 03 '25 10:06 amka

@amka The following works for me. The memory for the TextIter needs to be allocated first so that the native code can fill its data.

[DllImport(ImportResolver.Library, EntryPoint = "gtk_text_buffer_get_start_iter")]
public static extern void GetStartIter(IntPtr buffer, IntPtr iter);

[DllImport(ImportResolver.Library, EntryPoint = "gtk_text_buffer_get_end_iter")]
public static extern void GetEndIter(IntPtr buffer, IntPtr iter);

[DllImport(ImportResolver.Library, EntryPoint = "gtk_text_buffer_get_bounds")]
public static extern void GetBounds(IntPtr buffer, IntPtr start, IntPtr end);

[DllImport(ImportResolver.Library, EntryPoint = "gtk_text_buffer_get_iter_at_mark")]
public static extern void GetIterAtMark(IntPtr buffer, IntPtr iter, IntPtr mark);

public TextIter GetStartIter()
{
    var iter = new TextIter();
    Internal.TextBuffer.GetStartIter(Handle.DangerousGetHandle(), iter.Handle.DangerousGetHandle());
    return iter;
}

public TextIter GetEndIter()
{
    var iter = new TextIter();
    Internal.TextBuffer.GetEndIter(Handle.DangerousGetHandle(), iter.Handle.DangerousGetHandle());
    return iter;
}

public void GetBounds(out TextIter start, out TextIter end)
{
    start = new TextIter();
    end = new TextIter();
    Internal.TextBuffer.GetBounds(Handle.DangerousGetHandle(), start.Handle.DangerousGetHandle(), end.Handle.DangerousGetHandle());
}

public TextIter GetIterAtMark(TextMark mark)
{
    var iter = new TextIter();
    Internal.TextBuffer.GetIterAtMark(Handle.DangerousGetHandle(), iter.Handle.DangerousGetHandle(), mark.Handle.DangerousGetHandle());
    return iter;
}

ousnius avatar Sep 10 '25 21:09 ousnius

These methods are now generated with #1324

ousnius avatar Sep 25 '25 21:09 ousnius