Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Class struct methods are not exposed #283

Open
ju1ius opened this issue Apr 13, 2021 · 11 comments
Open

Class struct methods are not exposed #283

ju1ius opened this issue Apr 13, 2021 · 11 comments

Comments

@ju1ius
Copy link

ju1ius commented Apr 13, 2021

Hi,

It seems the gst_element_class_* methods are missing (i.e. gst_element_class_add_pad_template):

const gi = require('node-gtk')
const Gst = gi.require('Gst', '1.0')
Gst.init()

console.log(Gst.Element.addPadTemplate) // undefined
console.log(Gst.Element.prototype.addPadTemplate) // undefined
console.log(Gst.ElementClass) // undefined

Btw, congrats for this ambitious project ! 👍🏻

@romgrk
Copy link
Owner

romgrk commented Apr 13, 2021

From what I can see in the GIR file, GstElementClass is a gtype struct that isn't normally meant to be exposed in bindings (IIUC). We're currently filtering those out here:

if (GI.struct_info_is_gtype_struct(info))

g_struct_info_is_gtype_struct ()

gboolean
g_struct_info_is_gtype_struct (GIStructInfo *info);
Return true if this structure represents the "class structure" for some GObject or GInterface. This function is mainly useful to hide this kind of structure from generated public APIs.

Can you give an example use-case that you have for them? I'd prefer not to expose them, but if it's absolutely necessary so be it.

@ju1ius
Copy link
Author

ju1ius commented Apr 13, 2021

Can you give an example use-case that you have for them?

For example gst_element_class_add_pad_template is required to implement custom Gstreamer bins with dynamic proxy pads... More generally I believe these kinds of methods are required to implement custom Gstreamer plugins in the host language.
Theses methods are available in the python bindings. In particular, gst_element_class_add_pad_template is made available both as an instance method:

from gi.repository import Gst

class MyBin(Gst.Bin):
    def __init__(self):
        super().__init__(self)
        self._element = Gst.ElementFactory.make('someelement')
        self.add(self._element)
        tpl = Gst.PadTemplate.new(
            'audio_%u',
            Gst.PadDirection.SRC,
            Gst.PadPresence.REQUEST,
            Gst.Caps.from_string('audio/x-raw'),
        )
        self.add_pad_template(tpl)

    def do_request_new_pad(self, tpl: Gst.PadTemplate, name: str, caps: Gst.Caps):
        target = self._element.get_request_pad('src_%u')
        ghost_pad: Gst.GhostPad = Gst.GhostPad.new_from_template(name, target, tpl)
        self.add_pad(ghost_pad)
        return ghost_pad

and through the __gsttemplates__ class field mecanism:

from gi.repository import Gst

class MyBin(Gst.Bin):
    __gsttemplates__ = (
        Gst.PadTemplate.new(
            'audio_%u',
            Gst.PadDirection.SRC,
            Gst.PadPresence.REQUEST,
            Gst.Caps.from_string('audio/x-raw'),
        ),
    )

    def __init__(self):
        super().__init__(self)
        self._element = Gst.ElementFactory.make('someelement')
        self.add(self._element)

    def do_request_new_pad(self, tpl: Gst.PadTemplate, name: str, caps: Gst.Caps):
        target = self._element.get_request_pad('src_%u')
        ghost_pad: Gst.GhostPad = Gst.GhostPad.new_from_template(name, target, tpl)
        self.add_pad(ghost_pad)
        return ghost_pad

@romgrk
Copy link
Owner

romgrk commented Apr 13, 2021

Oh ok, pygobject approach seems to be more involved than I would like it to be, they probably have some custom code just for GST :/

Do you happen to have a minimal example in C showing what you're trying to do? I can work from that and add the missing parts. Maybe just removing the if-guard will work but I'm not sure.

@ju1ius
Copy link
Author

ju1ius commented Apr 14, 2021

Oh ok, pygobject approach seems to be more involved than I would like it to be, they probably have some custom code just for GST :/

No, the Gst.Element.add_pad_template() method is exposed automatically by pygobject, and it seems to be the standard behavior since it is also exposed by Vala...

The __gsttemplates__ mechanism is an override added by the gst-python package (reference).

@ju1ius
Copy link
Author

ju1ius commented Apr 14, 2021

So, I just wrote script to inspect the class struct methods, and it appears they are all exposed in vala.
Here's the output for the Gtk 3.0 module:

CellAreaClass

method: find_cell_property
symbol: gtk_cell_area_class_find_cell_property
exposed by node-gtk: no

method: install_cell_property
symbol: gtk_cell_area_class_install_cell_property
exposed by node-gtk: no

method: list_cell_properties
symbol: gtk_cell_area_class_list_cell_properties
exposed by node-gtk: no


CellRendererClass

method: set_accessible_type
symbol: gtk_cell_renderer_class_set_accessible_type
exposed by node-gtk: no


ContainerClass

method: find_child_property
symbol: gtk_container_class_find_child_property
exposed by node-gtk: no

method: handle_border_width
symbol: gtk_container_class_handle_border_width
exposed by node-gtk: no

method: install_child_properties
symbol: gtk_container_class_install_child_properties
exposed by node-gtk: no

method: install_child_property
symbol: gtk_container_class_install_child_property
exposed by node-gtk: no

method: list_child_properties
symbol: gtk_container_class_list_child_properties
exposed by node-gtk: no


WidgetClass

method: bind_template_callback_full
symbol: gtk_widget_class_bind_template_callback_full
exposed by node-gtk: no

method: bind_template_child_full
symbol: gtk_widget_class_bind_template_child_full
exposed by node-gtk: no

method: find_style_property
symbol: gtk_widget_class_find_style_property
exposed by node-gtk: no

method: get_css_name
symbol: gtk_widget_class_get_css_name
exposed by node-gtk: no

method: install_style_property
symbol: gtk_widget_class_install_style_property
exposed by node-gtk: no

method: list_style_properties
symbol: gtk_widget_class_list_style_properties
exposed by node-gtk: no

method: set_accessible_role
symbol: gtk_widget_class_set_accessible_role
exposed by node-gtk: no

method: set_accessible_type
symbol: gtk_widget_class_set_accessible_type
exposed by node-gtk: no

method: set_connect_func
symbol: gtk_widget_class_set_connect_func
exposed by node-gtk: no

method: set_css_name
symbol: gtk_widget_class_set_css_name
exposed by node-gtk: no

method: set_template
symbol: gtk_widget_class_set_template
exposed by node-gtk: no

method: set_template_from_resource
symbol: gtk_widget_class_set_template_from_resource
exposed by node-gtk: no

@ju1ius
Copy link
Author

ju1ius commented Apr 14, 2021

And here's the output for the Gst-1.0 module:

DeviceProviderClass

method: add_metadata
symbol: gst_device_provider_class_add_metadata
exposed by node-gtk: no

method: add_static_metadata
symbol: gst_device_provider_class_add_static_metadata
exposed by node-gtk: no

method: get_metadata
symbol: gst_device_provider_class_get_metadata
exposed by node-gtk: no

method: set_metadata
symbol: gst_device_provider_class_set_metadata
exposed by node-gtk: no

method: set_static_metadata
symbol: gst_device_provider_class_set_static_metadata
exposed by node-gtk: no


ElementClass

method: add_metadata
symbol: gst_element_class_add_metadata
exposed by node-gtk: no

method: add_pad_template
symbol: gst_element_class_add_pad_template
exposed by node-gtk: no

method: add_static_metadata
symbol: gst_element_class_add_static_metadata
exposed by node-gtk: no

method: add_static_pad_template
symbol: gst_element_class_add_static_pad_template
exposed by node-gtk: no

method: add_static_pad_template_with_gtype
symbol: gst_element_class_add_static_pad_template_with_gtype
exposed by node-gtk: no

method: get_metadata
symbol: gst_element_class_get_metadata
exposed by node-gtk: no

method: get_pad_template
symbol: gst_element_class_get_pad_template
exposed by node-gtk: no

method: get_pad_template_list
symbol: gst_element_class_get_pad_template_list
exposed by node-gtk: no

method: set_metadata
symbol: gst_element_class_set_metadata
exposed by node-gtk: no

method: set_static_metadata
symbol: gst_element_class_set_static_metadata
exposed by node-gtk: no

@ju1ius
Copy link
Author

ju1ius commented Apr 14, 2021

Output for the GObject 2.0 module:

ObjectClass

method: find_property
symbol: g_object_class_find_property
exposed by node-gtk: no

method: install_properties
symbol: g_object_class_install_properties
exposed by node-gtk: no

method: install_property
symbol: g_object_class_install_property
exposed by node-gtk: no

method: list_properties
symbol: g_object_class_list_properties
exposed by node-gtk: no

method: override_property
symbol: g_object_class_override_property
exposed by node-gtk: no

@ju1ius
Copy link
Author

ju1ius commented Apr 14, 2021

Using PyGObject:

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

btn = Gtk.Button()
print(btn.list_properties())
[<GParamString 'action-name'>,
 <GParamVariant 'action-target'>,
 <GParamObject 'related-action'>,
 <GParamBoolean 'use-action-appearance'>,
 <GParamString 'name'>,
 <GParamObject 'parent'>,
 <GParamInt 'width-request'>,
 <GParamInt 'height-request'>,
 <GParamBoolean 'visible'>,
 <GParamBoolean 'sensitive'>,
 <GParamBoolean 'app-paintable'>,
 <GParamBoolean 'can-focus'>,
 <GParamBoolean 'has-focus'>,
 <GParamBoolean 'is-focus'>,
 <GParamBoolean 'focus-on-click'>,
 <GParamBoolean 'can-default'>,
 <GParamBoolean 'has-default'>,
 <GParamBoolean 'receives-default'>,
 <GParamBoolean 'composite-child'>,
 <GParamObject 'style'>,
 <GParamFlags 'events'>,
 <GParamBoolean 'no-show-all'>,
 <GParamBoolean 'has-tooltip'>,
 <GParamString 'tooltip-markup'>,
 <GParamString 'tooltip-text'>,
 <GParamObject 'window'>,
 <GParamDouble 'opacity'>,
 <GParamBoolean 'double-buffered'>,
 <GParamEnum 'halign'>,
 <GParamEnum 'valign'>,
 <GParamInt 'margin-left'>,
 <GParamInt 'margin-right'>,
 <GParamInt 'margin-start'>,
 <GParamInt 'margin-end'>,
 <GParamInt 'margin-top'>,
 <GParamInt 'margin-bottom'>,
 <GParamInt 'margin'>,
 <GParamBoolean 'hexpand'>,
 <GParamBoolean 'vexpand'>,
 <GParamBoolean 'hexpand-set'>,
 <GParamBoolean 'vexpand-set'>,
 <GParamBoolean 'expand'>,
 <GParamInt 'scale-factor'>,
 <GParamUInt 'border-width'>,
 <GParamEnum 'resize-mode'>,
 <GParamObject 'child'>,
 <GParamString 'label'>,
 <GParamObject 'image'>,
 <GParamEnum 'relief'>,
 <GParamBoolean 'use-underline'>,
 <GParamBoolean 'use-stock'>,
 <GParamFloat 'xalign'>,
 <GParamFloat 'yalign'>,
 <GParamEnum 'image-position'>,
 <GParamBoolean 'always-show-image'>]

Using GJS:

imports.gi.versions.GObject = '2.0'
imports.gi.versions.Gtk = '3.0'
const GObject = imports.gi.GObject
const Gtk = imports.gi.Gtk

const btn = new Gtk.Button()
const propNames = GObject.Object.list_properties.call(btn).map(prop => prop.name)
print(propNames)
action-name,action-target,related-action,use-action-appearance,name,parent,width-request,height-request,visible,sensitive,app-paintable,can-focus,has-focus,is-focus,focus-on-click,can-default,has-default,receives-default,composite-child,style,events,no-show-all,has-tooltip,tooltip-markup,tooltip-text,window,opacity,double-buffered,halign,valign,margin-left,margin-right,margin-start,margin-end,margin-top,margin-bottom,margin,hexpand,vexpand,hexpand-set,vexpand-set,expand,scale-factor,border-width,resize-mode,child,label,image,relief,use-underline,use-stock,xalign,yalign,image-position,always-show-image

Using node-gtk:

const gi = require('node-gtk')
const Gtk = gi.require('Gtk', '3.0')

Gtk.init()
const btn = new Gtk.Button()
console.log(GObject.Object.listProperties.call(btn)) // Uncaught TypeError: GObject.Object.listProperties is not a function
console.log(btn.listProperties()) // Uncaught TypeError: btn.listProperties is not a function

@ju1ius
Copy link
Author

ju1ius commented Apr 14, 2021

a gtype struct that isn't normally meant to be exposed in bindings

In the light of the previous comments, I think you might want to reassess this statement (and thus maybe reopen #100 ?).
It seems to me that, even if the class structs themselves are not publicly exposed, at least their methods should be made available on the corresponding class constructor or prototype.
For the class struct fields, I don't know but it might be worth to investigate.

@ju1ius ju1ius changed the title Missing GstElementClass methods Class struct methods are not exposed Apr 14, 2021
@chfritz
Copy link
Contributor

chfritz commented Aug 13, 2024

I'd be very interested in access to g_object_class_list_properties as well. My use-case is like gst-inspect (see this line): I'm working with gstreamer and need to check which properties a specific gst element has. In different versions of gstreamer, these elements expose different properties. So in order to avoid an exception when trying to build a gstreamer pipeline with that element that uses a property that doesn't exist, I want to first check. I can probably work around it for now by using getProperty(NAME) !== undefined but that's kludgy and makes discovery very awkward.

@romgrk
Copy link
Owner

romgrk commented Aug 13, 2024

I found GObject.Object.interfaceListProperties but g_object_class_list_properties doesn't seem to be bound, not sure why. We might be missing a type of functions to add, it's listed under "class methods" in the docs, unlike g_object_interface_list_properties which is listed under "functions". I tried looking into it a bit but I don't have enough time at the moment, I might need to add a note that the repository doesn't receive regular maintenance.

I don't think it would be very hard to fix, the entry point to setup GIR entries is here if someone wants to have a go at it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants