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

RFC: Support vfunc overrides and interface implementations in user object types #110

Open
ghost opened this issue May 21, 2021 · 5 comments

Comments

@ghost
Copy link

ghost commented May 21, 2021

This is becoming more important with GTK4. Should look something like this (rough sample code):

(use-modules (gi) (gi repository))
(require "Gtk" "4.0")
(load-by-name "Gtk" "Widget")
(load-by-name "Gtk" "BoxLayout")
(load-by-name "Gtk" "Scrollable")
(load-by-name "Gtk" "SizeRequestMode")

(register-type "MyWidget" <GtkWidget> #f #f
  ; class initializer
  #:class-init (lambda (class)
    (widget-class:set-layout-manager-type class <GtkBoxLayout>)
    (widget-class:set-template-from-resource class "/my-widget.ui"))

  ; interface implementation
  (implement-interface <GtkScrollable>
    #:get-border (lambda (self) (list #f #f)))

  ; instance initializer
  #:init (lambda (self)
    (widget:init-template self))

  ; vfunc overrides
  #vfunc-get-request-mode (lambda (self)
    (symbol->size-request-mode 'constant-size))
  #vfunc-measure (lambda (self orientation for-size)
    (list 200 200 #f #f)))
@ghost ghost changed the title Support vfunc overrides and interface implementations Support vfunc overrides and interface implementations in user object types May 21, 2021
@ghost
Copy link
Author

ghost commented May 21, 2021

It would also be nice to have a more idiomatic way to declare properties and signals, and to declare templates:

(use-modules (gi) (gi repository))
(load-all "Gtk" "4.0") ; syntax sugar for require and typelib->module

(define-type <MyWidget> <GtkWidget>

  ; long property definition, should be able to take some guile types
  ((my-int-prop <integer> #:nick "My Int Prop" #:description "Long Description"
                          #:default 1 #:min 0 #:max 10)

   ; short property syntax, gtype also works
   (my-uint-prop G_TYPE_UINT "My Uint Prop" "Long Description" 10 0 100)

   ; using #:getter and/or #setter won't allocate internal storage
   (my-object-prop <GtkAdjustment> #:construct? #t
     #:getter (lambda (self) (range:get-adjustment (template-child-ref self 'my-range)))
     #:setter (lambda (self adj) (range:set-adjustment (template-child-ref self 'my-range) adj))))

  ; short signal syntax, return type defaults to none
  ((my-detailed-signal #:flags (detailed))
   ; parameters can take guile types
   (my-param-signal <string> <int> <GtkWidget> #:return-type <int> #:accumulator true-handled))

  ; setup template in class constructor
  (template-resource "/my-widget.ui")
  ; allocates storage for a template child and automatically calls bind_template_child_full
  ; the type is necessary so we can instantiate it before loading the template
  ; the object can later be accessed with template-child-ref
  (template-child my-range <GtkRange>)
  ; automatically calls bind_template_callback_full
  (template-callback range-changed (self range) (display (range:get-value range))))

@ghost ghost changed the title Support vfunc overrides and interface implementations in user object types RFC: Support vfunc overrides and interface implementations in user object types May 22, 2021
@LordYuuma
Copy link
Collaborator

Note, that stuff like implement-interface won't work as part of register-type, since it's just a procedure. That said, there should be some way to make interface definitions from scheme through register-type.

As for the template stuff, I don't think that what you want can easily be achieved (Guile-GI would have to make use of GtkBuilder, which might not be the same GtkBuilder you want). I'd prefer if you directly worked with the GtkBuilder API there, perhaps even ditching the XML – sxml is a better representation anyway. See the builder-manual example for how to create a builder on your own and use it.

@ghost
Copy link
Author

ghost commented May 29, 2021

Right, so my thoughts are this should be done with a new macro called define-gtype or something like that to add some syntax sugar, similar to goops define-class.

My idea with supporting this would be to avoid interacting with Gtk from the C code. It could be done similar to way that the python and javascript bindings do it by injecting some code at runtime using "overrides," after the gir typelib is loaded: Overrides/Gtk.py, overrides/Gtk.js. Both of those avoid the linking problem. It could probably also be done only with macros, if it was desired to avoid changing the C code at all.

I agree that SXML should be preferred, but templates are still going to be wanted for Gtk4, some things (such as widget children and the layout system) are really not easy to do through GtkBuilder. For that, the SXML can be converted (maybe even at compile time) and then passed to gtk_widget_class_set_template.

@LordYuuma
Copy link
Collaborator

Sure, sugar is always nice to have, but atm we're lacking the groundwork, that this sugar would need.

As for interfacing with Gtk, GLib, etc. it doesn't much matter whether we do it in C or Scheme (though obviously we would prefer Scheme), such overrides already run counter to previous design choices, e.g. the choice to allow limited loading of typelibs.

I'm not quite sure what we would need to/can do to support gtk_widget_class_set_template. To be honest, I think you should be able to do everything you can do with templates through the Builder API directly, but alas, some will still want to use Glade for UI design. If we manage to allocate arbitrarily-sized GObjects (with arbitarily sized privates), we can call stuff like gtk_widget_class_bind_template_child_full, so perhaps there ought to be a way of specifying the layout of the struct we generate. That said, given that all of this is implemented mostly via C macros, I don't have high hopes for it.

@ghost
Copy link
Author

ghost commented Jun 9, 2021

To handle this is something that needs to be done at class/instance construct time, so it would be possible to only do the override when a particular type definition of GtkWidget is loaded, and then ensure that the appropriate symbols are referenced only then, using the same typelib as the class. Features can further be gated by checking the loaded version of the library.

I would have to do a bit of hacking to see how the groundwork would look, I'll submit a draft PR if I get a chance to do that, then probably a comparison could be done to see how it compares to GtkBuilder.

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

1 participant