Giter Site home page Giter Site logo

Comments (7)

diamondburned avatar diamondburned commented on May 24, 2024 2

New proposal:

type Gadget struct {
	gtk.Widget
	Child gtk.Widgetter `glib:"child,Construct,ConstructOnly"`
}

var gadgetType = glib.RegisterSubclass[*Gadget](
	glib.WithParamSpecs([]glib.ParamSpec{
		// TODO
	}),
)

func NewGadget(child gtk.Widgetter) *Gadget {
	return gadgetType.NewWithProperties(map[string]any{
		"child": child,
	})
}

from gotk4.

diamondburned avatar diamondburned commented on May 24, 2024 1

Update: subclassing is now on the main branch. Things might be very unstable; please report bugs and crashes to issues.

A release will be made that points to the last working pre-subclassing commit, just to mitigate this potential instability.

from gotk4.

diamondburned avatar diamondburned commented on May 24, 2024

Generate these:

// OverrideWidget creates a new Widget from the given overrider.
func OverrideWidget(overrider WidgetOverrider) Widget {
	obj := externglib.Register(externglib.Type(C.gtk_widget_get_type()), overrider)
	return wrapWidget(obj)
}

To implement a new widget, the user can do this to subclass a widget:

type Widget struct {
	gtk.Widget       // ours
	label *gtk.Label // theirs
}

// Note that we're making methods that implement Overrider. The actual
// Widget instance MIGHT NOT implement this.
var _ gtk.WidgetOverrider = (*Widget)(nil)

func NewWidget(label string) *Widget {
	w := Widget{
		label: gtk.NewLabel(label),
	}
	w.Widget = gtk.OverrideWidget(w)
	return &w
}

func (w *Widget) Snapshot(s *gtk.Snapshot) {}

And they can use it like so:

w := NewWidget("Hello, world!")

b := gtk.NewBox(gtk.OrientationVertical, 0)
b.Append(w)

Or they can do this to implement an abstract class or interface:

type HTTPMedia struct {
	gtk.MediaStream
}

func NewHTTPMedia() gtk.MediaStreamer {
	h := HTTPMedia{}
	h.MediaStream = gtk.OverrideMediaStreamer(&h)
	return &h
}

func (h *HTTPMedia) Pause() {}
func (h *HTTPMedia) Play() {}

It might be worth it to make glib.Object work for both C and Go objects,
though. The user will no longer need to embed glib.GoObject if so.

If this is the case (and the examples are already applied as such), then
OverrideX functions will rely on glib.Object's specific methods to determine
if it's a C or Go object.

It is important to note that the Object's implementation for Go
subclassing/implementing will have to check that the Object instance isn't
already a valid C instance. Once the check passes, it can then create a new
Object and swap that in place.

It might be quite troublesome for a Go GObject class to extend another Go class,
because at that point, it wouldn't be dealing with just abstract classes
anymore, rather actual classes. This is basically dealing with inheritance,
which might not be a good idea.

Since GTK4 is shifting from the inheritance paradigm to a more composition-like
one, it might not be worth the effort to consider this in the implementation.
The user is expected to create a struct that implements the overrider for each
layer, anyway.

For example, if someone makes a Window struct that implements
WidgetOverrider, and someone else wants to "extend" it, then that user is
expected to rewrite all the methods. Of course, Go's struct embedding will help
save some of that work, however, so it should just work normally. It's worth
noting that by going with this approach, each layer will have to create a new
GObject on the C side, each with its own GType.

The code will look roughly like this:

type OtherWidget struct {
	Widget
	box *gtk.Box
}

func NewOtherWidget() *OtherWidget {
	w := OtherWidget{
		Widget: NewWidget("Hello, world!"),
		box:    gtk.NewBox(),
	}
	w.Widget.Widget = gtk.OverrideWidget(&w)
	return &w
}

The only quirk with this method is that it requires the caller to manually dive
down the embedding tree to override the inner widget instance while throwing
away the old Widget's internal object. This isn't very ideal. It could also be
the reason that doing code in Init() would be a better idea.

Maybe externglib.Register could recognize the previous Object allocated and
reuse that instead of creating a new one. It might not always be possible,
though.

There's also the issue of registering for signals. As for properties, it can
probably be done like this:

	// NewOtherWidget...

	w.AddProperties(map[string]interface{}{
		"fold": false,
	})

Old Draft:

Note that for all types that the user can override/implement, the methods
and functions will always take in an interface type, e.g. Widgetter. This
means that the functions will always check if the type is an Object or a
GoObject. In both cases, the type is expected to implement the entire
interface.

Also note that there's no need for the user to implement Init, Dispose and
Finalize. Those methods are only there so the user can use it, but there's
not really a good reason to do so. Objects that are inside the struct are
all GC'd in undefined order, which doesn't really matter, since by the time
they need to be finalized by the GC, everything wouldn't have been
referenced anymore.

Also note that NewClass will basically register a new GType, and that's it.
It should be a fairly cheap call, since sync.Map can prove to be very cheap
after a while, and we're only ever growing that map.

The map will probably be a reflect.Type to a GType map. It'll basically
provide type interning similar to GLib while abstracting the Type method
away from the user nicely.

The Register function will definitely need a valid GoObject instance, though
note that the user didn't have to construct the type. As long as we have a
valid zero-value of it, we can easily do that ourselves in Register. This
means the user will not have to do any heavy-lifting.

from gotk4.

diamondburned avatar diamondburned commented on May 24, 2024

Created the subclassing branch to keep track of this.

from gotk4.

diamondburned avatar diamondburned commented on May 24, 2024

As for properties, it can
probably be done like this:

This API doesn't work. The properties have to be set during construction of the
object as well.

Perhaps this might:

func OverrideWidget(w gtk.WidgetOverrider, opts ...glib.ObjectOptions)

gtk.OverrideWidget(w, glib.WithProperties{
	"fold": false,
})

from gotk4.

diamondburned avatar diamondburned commented on May 24, 2024

See ./gtype.c:4115 g_type_check_instance_cast and ``G_TYPE_CIC`.

from gotk4.

diamondburned avatar diamondburned commented on May 24, 2024

Crashing with

2022/12/20 05:18:46 Critical: GLib-GObject: validate_and_install_class_property: assertion 'class->set_property != NULL' failed
2022/12/20 05:18:46 Critical: GLib-GObject: g_object_new_is_valid_property: object class 'AdaptiveFold' has no property named 'position'

This could be gotk4 not calling parent class initializers.

from gotk4.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.