Custom signals in GTKSharp

Viewed 608

The context

I'm converting a C/GTK+ GUI application to C#. I'm using the GTKSharp bindings version 3.22.0 in VS2017.

The application declares several signals like

g_signal_new ("SIG_NAME", params...);

and emits them via g_signal_emit_by_name(... "SIG_NAME"...).

The problem

I can't find a way to translate that behaviour into GTK#.

I've looked into GTK#'s source code to see how custom signals are defined and handled, like here, but I haven't been able to mimic the behaviour implemented there.

The approach

  1. Approach #1

I've tried defining a custom object like this:

using System;
using Gtk;

public class MyApp
{
    public class MyCustomObj : GLib.Object
    {
        public delegate void MyDelegateSignalHandler(int arg0, int arg1);
        public delegate void MyDelegate(int arg0, int arg1);
        public class MyDelegateArgs : GLib.SignalArgs
        {
            public int a { get; set; }
        }
        public MyCustomObj() : base()
        {}
        [GLib.Signal("MyEvent")]
        public event MyDelegate MyDelegateEvent
        {
            add
            {
                GLib.Object.GetObject(Handle).AddSignalHandler("MyEvent", value, new MyDelegateSignalHandler((a, b) => { }));
            }
            remove
            {
                GLib.Object.GetObject(Handle).RemoveSignalHandler("MyEvent", value);
            }
        }
    }

    public static void Main(string[] args)
    {
        MyCustomObj newObj = new MyCustomObj();
        newObj.MyDelegateEvent += new MyCustomObj.MyDelegate((a, b) => { });
        GLib.Signal.Emit(newObj, "MyEvent", 1, 2);
    }
}

That is:

  1. A custom GLib object type, MyCustomObj, is declared
  2. A MyDelegate event is declared
  3. An instance of MyCustomObj is created and a callback is attached to its new event
  4. A MyEvent signal is emitted.

When AddSignalHandler() is called, however, GTK isn't too happy about that:

(CustomSignal.exe:9276): GLib-GObject-[1;33mWARNING[0m **: ../../glib-2.50.2/gobject/gsignal.c:2423: signal 'MyEvent' is invalid for instance '05cc4000' of type '__gtksharp_0_MyApp+2bMyCustomObj'

And therefore GLib.Signal.Emit reports

Invalid signal name: MyEvent
  1. Approach #2

However, GObject's definition uses AddSignalHandler this way:

public void AddNotification (string property, NotifyHandler handler)
{
    AddSignalHandler ("notify::" + property, handler, typeof(NotifyArgs));
}

So it seems that a signal named notify::<whatever> is handled just fine. Let's try this:

public class MyCustomObj : GLib.Object
{
    public MyCustomObj() : base()
    {}
    [GLib.Signal("notify::abc")]
    public event GLib.NotifyHandler MyDelegateEvent
    {
        add
        {
            GLib.Object.GetObject(Handle).AddSignalHandler("notify::abc", value, typeof(GLib.NotifyArgs));
        }
        remove
        {
            GLib.Object.GetObject(Handle).RemoveSignalHandler("notify::acb", value);
        }
    }
}

public static void Main(string[] args)
{
    MyCustomObj newObj = new MyCustomObj();
    newObj.MyDelegateEvent += new GLib.NotifyHandler((o, e) => { Console.WriteLine("Signal received"); });
    GLib.Signal.Emit(newObj, "notify::abc");
    Console.ReadLine();
}

And this actually works. Moreover, [GLib.Signal("notify::abc")] is unnecessary as the signal is correctly registered and handled. Renaming the signal name to anything that is not notify::..., however, causes the application to raise the usual warning:

(CustomSignal.exe:9276): GLib-GObject-[1;33mWARNING[0m **: ../../glib-2.50.2/gobject/gsignal.c:2423: signal '...' is invalid for instance '05cc4000' of type '__gtksharp_0_MyApp+2bMyCustomObj'

I could use a hand as I'm out of ideas.

0 Answers
Related