gtkd-developers / GtkD

GtkD is a D binding and OO wrapper of GTK+ originally created by Antonio Monteiro
http://gtkd.org
Other
322 stars 71 forks source link

wrapping goocanvas #185

Closed hyOzd closed 7 years ago

hyOzd commented 7 years ago

Hi, I'm trying to create wrappers for GooCanvas library and I'm having some trouble that I hope you can help with.

Currently there is not much in my APILookupGooCanvas.txt file:

wrap: goocanvas
file: /usr/share/gir-1.0/GooCanvas-2.0.gir

addAliases: start
    public import gtkc.cairotypes;
    public import gtkc.gdkpixbuftypes;
    public import gtkc.gdktypes;
    public import gtkc.gtktypes;
addAliases: end

There are two interfaces defined in GooCanvas; CanvasItem and CanvasItemModel. When I run the wrapper as it is, it creates these modules for CanvasItem: CanvasItemModelT.d and CanvasItemModelIF.d . Both these modules have this import line that causes a compilation error because it doesn't exist!

private import goocanvas.CanvasItem;

The symbol CanvasItem is also referenced throughout the code, for ex. from CanvasItemIF.d file:

public CanvasItemIF getChild(int childNum)
{
    auto p = goo_canvas_item_get_child(getCanvasItemStruct(), childNum);

    if(p is null)
    {
        return null;
    }

    return ObjectG.getDObject!(CanvasItem, CanvasItemIF)(cast(GooCanvasItem*) p);
}

All usages of 'CanvasItem' for a ObjectG.getDObject call.

But there is no CanvasItem.d module created. I checked some interfaces used in Gtk, and as far as I understand they don't require any special attention in lookup.txt file.

What should I do in this case? Any help is appreciated.

MikeWey commented 7 years ago

You should provide an minimal implementation for CanvasItem.

You can do this by adding this to the APILookup file:

struct:
class: CanvasItem
extend: GObject.Object
implements: CanvasItem
hyOzd commented 7 years ago

Thanks a lot @MikeWey this seems to work.

Now I'm having problems with events (along with other problems that I haven't investigated yet). Specifically addEvents method. Here is the code generated for 'focus-in' event of CanvasItem:

    gulong addOnFocusIn(bool delegate(CanvasItemIF, Event, CanvasItemIF) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
    {
        addEvents(EventMask.FOCUS_CHANGE_MASK);
        onFocusInListeners ~= new OnFocusInDelegateWrapper(dlg, 0, connectFlags);
        onFocusInListeners[onFocusInListeners.length - 1].handlerId = Signals.connectData(
            this,
            "focus-in-event",
            cast(GCallback)&callBackFocusIn,
            cast(void*)onFocusInListeners[onFocusInListeners.length - 1],
            cast(GClosureNotify)&callBackFocusInDestroy,
            connectFlags);
        return onFocusInListeners[onFocusInListeners.length - 1].handlerId;
    }

GooCanvas doesn't have a method named "add_events". My understanding from the gtk documentation is that this method is required because events that a gtk widget receives are filtered according to its event mask. To receive a certain event it has to be added to its event mask. As far as I can see GooCanvas doesn't have this functionality thus addEvents isn't required at all.

If I'm correct about removing addEvents where should this be done? Adding another exception here maybe?

hyOzd commented 7 years ago

Another problem that I couldn't figure out. CanvasItemT::getTransform method is created like this:

    public bool getTransform(out Matrix transform)
    {
        cairo_matrix_t* outtransform = gMalloc!cairo_matrix_t();

        auto p = goo_canvas_item_get_transform(getCanvasItemStruct(), outtransform) != 0;

        transform = new Matrix(outtransform, true); // ERROR HERE

        return p;
    }

Problem is cairo.Matrix doesn't have such a constructor?

MikeWey commented 7 years ago

Both cases should be fixed with the latest commit.

hyOzd commented 7 years ago

@MikeWey there is a typo here. One extra comma.

Now I have this error, but I haven't investigated this one myself yet:

src/goocanvas/CanvasWidgetAccessibleFactory.d(33): src/goocanvas/CanvasAccessibleFactory.d(33): Error: class goocanvas.CanvasAccessibleFactory.CanvasAccessibleFactory cannot implicitly generate a default ctor when base class atk.ObjectFactory.ObjectFactory is missing a default ctor
Error: class goocanvas.CanvasWidgetAccessibleFactory.CanvasWidgetAccessibleFactory cannot implicitly generate a default ctor when base class atk.ObjectFactory.ObjectFactory is missing a default ctor
src/goocanvas/CanvasItemAccessibleFactory.d(33): Error: class goocanvas.CanvasItemAccessibleFactory.CanvasItemAccessibleFactory cannot implicitly generate a default ctor when base class atk.ObjectFactory.ObjectFactory is missing a default ctor
MikeWey commented 7 years ago

Fixed in bac77c84043cf136aaa0559e3f8a952c18a04663

hyOzd commented 7 years ago

Finally got it working.

goocanvas

I think the last problem was caused by the GIR file. Because the library doesn't contain these classes: CanvasWidgetAccessibleFactory, CanvasWidgetAccessibleFactory, CanvasItemAccessibleFactory. At least the version distributed in mint doesn't. Adding 'noCode' for them in the lookup file solved the issue.

Now I have a question; I believe it's my responsibility to add missing constructors as member functions. For example for CanvasRect I added this constructor via API lookup file.

struct: CanvasRect
code: start
public this (CanvasItemIF parent, double x, double y, double width, double height)
{
    auto p = parent.getCanvasItemStruct();
    auto item = goo_canvas_rect_new(p, x, y, width, height);

    this (cast(GooCanvasRect*) item);
} 
code: end

Is this the correct approach? I want to be sure before moving on to others.

hyOzd commented 7 years ago

Here is another problem that I couldn't figure out. Actually I found a workaround for it but I'm not sure about it.

Below is the generated wrapper for goo_canvas_item_model_class_list_child_properties function:

    public static ParamSpec[] classListChildProperties(ObjectClass mclass)
    {
        uint nProperties;

        auto p = goo_canvas_item_model_class_list_child_properties((mclass is null) ? null : mclass.getObjectClassStruct(), &nProperties);

        if(p is null)
        {
            return null;
        }

        ParamSpec[] arr = new ParamSpec[nProperties];
        for(int i = 0; i < nProperties; i++)
        {
            arr[i] = ObjectG.getDObject!(ParamSpec)(cast(*) &p[i]); // ERROR HERE
        }

        return arr;
    }

Above code doesn't compile due to missing cast type. I checked other similar functions and it turns out there is a problem with the gir file entry of this function. Functions return value is missing the c:type field for GObject.ParamSpec. Here is the relevant section from gir file:

    <return-value transfer-ownership="container">
        <doc xml:space="preserve">
 a newly allocated array of #GParamSpec*. The array must be freed with g_free().</doc>
        <array length="1" zero-terminated="0" c:type="GParamSpec**">
          <type name="GObject.ParamSpec"/>
        </array>
      </return-value>

Other similar functions have it defined like this: <type name="GObject.ParamSpec" c:type="GParamSpec*"/> . So I changed above line and added tye c:type field in the GIR file and compilation succeeded.

My question is how can I solve this without hacking the GIR file?

MikeWey commented 7 years ago

For the constructors, on ArchLinux the definition in the gir file would be detected as an constructor.

There are two cases that are currently detected as a constructor: The function is defined with an constructor tag, or if its defined with an function tag and its name starts with "new".

For the missing cast, you can add:

structWrap: GParamSpec* ParamSpec

to the APILookup file. but the changes from commit 1c8a14bee4494298b5a5911d589e4b4dcdb0ca9f should also take care of this.

hyOzd commented 7 years ago

@MikeWey I don't understand, what is different in arch? I've checked the GIR file in this arch package and function is defined the same way with this tag:

      <function name="new"
                c:identifier="goo_canvas_rect_new"
                introspectable="0">

It is not defined with a constructor tag but its name is "new". Is it the introspectable="0"?


By the way the thanks for the fix. (workaround you suggested didn't work FYI)

In the mean time I've started to push my work here for anyone interested.

hyOzd commented 7 years ago

I've investigated other libraries a bit and it seems that other functions with similar signatures are generated just fine. For ex this one: pango_attr_font_desc_new .

hyOzd commented 7 years ago

I think it is skipped because it is variadic. Am I right?

MikeWey commented 7 years ago

That is correct, variadic functions are currently skipped.

hyOzd commented 7 years ago

That is correct, variadic functions are currently skipped.

In most cases variadic parameter is optional and used to pass property-value pairs to constructors. So it can be ignored. I was wondering if we could have another tag implemented in API lookup file that would instruct the wrapper to ignore variadic parameter of the function?

hyOzd commented 7 years ago

I went ahead, and added a new tag for API lookup file called noVariadic for ignoring (removing) variadic parameter of a function. Here. It worked. But then I noticed these runtime errors in running application:

(main:27620): GLib-GObject-WARNING **: g_object_set_valist: object class 'GooCanvasRect' has no property named '\xc0\xf6\x82'

Turns out goocanvas API expect variadic list to be ended with a null. So, variadic parameter is not entirely optional. I guess I will add constructors manually. There aren't that many after all.